source: trunk/src/kernel32/wprocess.cpp

Last change on this file was 22131, checked in by dmik, 9 years ago

Fix processing of command line provided by kLIBC executables.

This fixes two problems:

  • Breaking arguments with spaces into multiple arguments instead of one.
  • Losing double quotes which are part of argument's contents.
File size: 114.2 KB
Line 
1/* $Id: wprocess.cpp,v 1.194 2004-02-24 11:46:10 sandervl Exp $ */
2
3/*
4 * Win32 process functions
5 *
6 * Copyright 1998-2000 Sander van Leeuwen (sandervl@xs4all.nl)
7 * Copyright 2000 knut st. osmundsen (knut.stange.osmundsen@mynd.no)
8 * Copyright 2003 Innotek Systemberatung GmbH (sandervl@innotek.de)
9 *
10 *
11 * NOTE: Even though Odin32 OS/2 apps don't switch FS selectors,
12 * we still allocate a TEB to store misc information.
13 *
14 * TODO: What happens when a dll is first loaded as LOAD_LIBRARY_AS_DATAFILE
15 * and then for real? (first one not freed of course)
16 *
17 * Project Odin Software License can be found in LICENSE.TXT
18 *
19 */
20#include <odin.h>
21#include <odinwrap.h>
22#include <os2win.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27#ifdef __KLIBC__
28#include <klibc/startup.h>
29#endif
30
31#include <unicode.h>
32#include "windllbase.h"
33#include "winexebase.h"
34#include "windllpeldr.h"
35#include "winexepeldr.h"
36#include "windlllx.h"
37#include <vmutex.h>
38#include <handlemanager.h>
39#include <odinpe.h>
40
41#include "odin32validate.h"
42#include "exceptutil.h"
43#include "asmutil.h"
44#include "oslibdos.h"
45#include "oslibmisc.h"
46#include "oslibdebug.h"
47#include "hmcomm.h"
48
49#include "console.h"
50#include "wincon.h"
51#include "versionos2.h" /*PLF Wed 98-03-18 02:36:51*/
52#include <wprocess.h>
53#include "mmap.h"
54#include "initterm.h"
55#include "directory.h"
56#include "shellapi.h"
57
58#include <win/ntddk.h>
59#include <win/psapi.h>
60#include <win/options.h>
61
62#include <custombuild.h>
63
64#define DBG_LOCALLOG DBG_wprocess
65#include "dbglocal.h"
66
67#ifdef PROFILE
68#include <perfview.h>
69#include <profiler.h>
70#endif /* PROFILE */
71
72
73ODINDEBUGCHANNEL(KERNEL32-WPROCESS)
74
75
76//environ.cpp
77char *CreateNewEnvironment(char *lpEnvironment);
78
79/*******************************************************************************
80* Global Variables *
81*******************************************************************************/
82BOOL fIsOS2Image = FALSE; /* TRUE -> Odin32 OS/2 application (not converted!) */
83 /* FALSE -> otherwise */
84BOOL fSwitchTIBSel = FALSE; // TRUE -> switch TIB selectors
85 // FALSE -> don't
86BOOL fForceWin32TIB = FALSE; // TRUE -> force TIB switch
87 // FALSE -> not enabled
88BOOL fExitProcess = FALSE;
89
90//Commandlines
91PCSTR pszCmdLineA; /* ASCII/ANSII commandline. */
92PCWSTR pszCmdLineW; /* Unicode commandline. */
93char **__argvA = NULL; /* command line arguments in ANSI */
94int __argcA = 0; /* number of arguments in __argcA */
95
96//Process database
97PDB ProcessPDB = {0};
98ENVDB ProcessENVDB = {0};
99CONCTRLDATA ProcessConCtrlData = {0};
100STARTUPINFOA StartupInfo = {0};
101CHAR unknownPDBData[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 ,0 ,0};
102USHORT ProcessTIBSel = 0;
103DWORD *TIBFlatPtr = 0;
104
105//list of thread database structures
106static TEB *threadList = 0;
107static VMutex threadListMutex;
108
109/**
110 * LoadLibraryExA callback for LX Dlls, it's call only on the initial load.
111 * Maintained by ODIN_SetLxDllLoadCallback().
112 * Note! Because of some hacks it may also be called from Win32LxDll::Release().
113 */
114PFNLXDLLLOAD pfnLxDllLoadCallback = NULL;
115
116extern "C" {
117
118//******************************************************************************
119//******************************************************************************
120VOID WIN32API ForceWin32TIB()
121{
122 if(!fForceWin32TIB) {
123 ODIN_SetTIBSwitch(TRUE);
124 fForceWin32TIB = TRUE;
125 }
126 return;
127}
128//******************************************************************************
129//******************************************************************************
130TEB *WIN32API GetThreadTEB()
131{
132 if(TIBFlatPtr == NULL) {
133 return 0;
134 }
135 return (TEB *)*TIBFlatPtr;
136}
137//******************************************************************************
138//******************************************************************************
139TEB *WIN32API GetTEBFromThreadId(ULONG threadId)
140{
141 TEB *teb = threadList;
142
143 threadListMutex.enter();
144 while(teb) {
145 if(teb->o.odin.threadId == threadId) {
146 break;
147 }
148 teb = teb->o.odin.next;
149 }
150 threadListMutex.leave();
151 return teb;
152}
153//******************************************************************************
154//******************************************************************************
155TEB *WIN32API GetTEBFromThreadHandle(HANDLE hThread)
156{
157 TEB *teb = threadList;
158
159 threadListMutex.enter();
160 while(teb) {
161 if(teb->o.odin.hThread == hThread) {
162 break;
163 }
164 teb = teb->o.odin.next;
165 }
166 threadListMutex.leave();
167 return teb;
168}
169//******************************************************************************
170//Allocate TEB structure for new thread
171//******************************************************************************
172TEB *WIN32API CreateTEB(HANDLE hThread, DWORD dwThreadId)
173{
174 USHORT tibsel;
175 TEB *winteb;
176
177 if(OSLibAllocSel(sizeof(TEB), &tibsel) == FALSE)
178 {
179 dprintf(("InitializeTIB: selector alloc failed!!"));
180 DebugInt3();
181 return NULL;
182 }
183 winteb = (TEB *)OSLibSelToFlat(tibsel);
184 if(winteb == NULL)
185 {
186 dprintf(("InitializeTIB: DosSelToFlat failed!!"));
187 DebugInt3();
188 return NULL;
189 }
190 memset(winteb, 0, sizeof(TEB));
191 dprintf(("TIB selector %x; linaddr 0x%x", tibsel, winteb));
192
193 threadListMutex.enter();
194 TEB *teblast = threadList;
195 if(!teblast) {
196 threadList = winteb;
197 winteb->o.odin.next = NULL;
198 }
199 else {
200 while(teblast->o.odin.next) {
201 teblast = teblast->o.odin.next;
202 }
203 teblast->o.odin.next = winteb;
204 }
205 threadListMutex.leave();
206
207 winteb->except = (PVOID)-1; /* 00 Head of exception handling chain */
208 winteb->htask16 = (USHORT)OSLibGetPIB(PIB_TASKHNDL); /* 0c Win16 task handle */
209 winteb->stack_sel = getSS(); /* 0e 16-bit stack selector */
210 winteb->self = winteb; /* 18 Pointer to this structure */
211 winteb->flags = TEBF_WIN32; /* 1c Flags */
212 winteb->queue = 0; /* 28 Message queue */
213 winteb->tls_ptr = &winteb->tls_array[0]; /* 2c Pointer to TLS array */
214 winteb->process = &ProcessPDB; /* 30 owning process (used by NT3.51 applets)*/
215 winteb->delta_priority = THREAD_PRIORITY_NORMAL;
216 winteb->process = &ProcessPDB;
217
218 //store selector of new TEB
219 winteb->teb_sel = tibsel;
220
221 winteb->o.odin.hThread = hThread;
222 winteb->o.odin.threadId = dwThreadId;
223
224 // Event semaphore (auto-reset) to signal message post to MsgWaitForMultipleObjects
225 winteb->o.odin.hPostMsgEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
226
227 return winteb;
228}
229//******************************************************************************
230// Set up the TIB selector and memory for the main thread
231//******************************************************************************
232TEB *WIN32API InitializeMainThread()
233{
234 HANDLE hThreadMain;
235 TEB *teb;
236
237 //Allocate one dword to store the flat address of our TEB
238 dprintf(("InitializeMainThread Process handle %x, id %x", GetCurrentProcess(), GetCurrentProcessId()));
239
240 TIBFlatPtr = (DWORD *)OSLibAllocThreadLocalMemory(1);
241 if(TIBFlatPtr == 0) {
242 dprintf(("InitializeTIB: local thread memory alloc failed!!"));
243 DebugInt3();
244 return NULL;
245 }
246 //SvL: This doesn't really create a thread, but only sets up the
247 // handle of thread 0
248 hThreadMain = HMCreateThread(NULL, 0, 0, 0, 0, 0, TRUE);
249
250 //create and initialize TEB
251 teb = CreateTEB(hThreadMain, GetCurrentThreadId());
252 if(teb == NULL || InitializeThread(teb, TRUE) == FALSE) {
253 DebugInt3();
254 return NULL;
255 }
256
257 ProcessTIBSel = teb->teb_sel;
258
259 //todo initialize PDB during process creation
260 //todo: initialize TLS array if required
261 //TLS in executable always TLS index 0?
262//// ProcessPDB.exit_code = 0x103; /* STILL_ACTIVE */
263 ProcessPDB.threads = 1;
264 ProcessPDB.running_threads = 1;
265 ProcessPDB.ring0_threads = 1;
266 ProcessPDB.system_heap = GetProcessHeap();
267 ProcessPDB.parent = 0;
268 ProcessPDB.group = &ProcessPDB;
269 ProcessPDB.priority = 8; /* Normal */
270 ProcessPDB.heap = ProcessPDB.system_heap; /* will be changed later on */
271 ProcessPDB.next = NULL;
272 ProcessPDB.winver = 0xffff; /* to be determined */
273 ProcessPDB.server_pid = (void *)GetCurrentProcessId();
274 ProcessPDB.tls_bits[0] = 0; //all tls slots are free
275 ProcessPDB.tls_bits[1] = 0;
276
277 GetSystemTime(&ProcessPDB.creationTime);
278
279 /* Initialize the critical section */
280 InitializeCriticalSection(&ProcessPDB.crit_section );
281
282 //initialize the environment db entry.
283 ProcessPDB.env_db = &ProcessENVDB;
284 ProcessENVDB.startup_info = &StartupInfo;
285 ProcessENVDB.environ = GetEnvironmentStringsA();
286 ProcessENVDB.cmd_line = (CHAR*)(void*)pszCmdLineA;
287 ProcessENVDB.cmd_lineW = (WCHAR*)(void*)pszCmdLineW;
288 ProcessENVDB.break_handlers = &ProcessConCtrlData;
289 ProcessConCtrlData.fIgnoreCtrlC = FALSE; /* TODO! Should be inherited from parent. */
290 ProcessConCtrlData.pHead = ProcessConCtrlData.pTail = (PCONCTRL)malloc(sizeof(CONCTRL));
291 ProcessConCtrlData.pHead->pfnHandler = (void*)DefaultConsoleCtrlHandler;
292 ProcessConCtrlData.pHead->pNext = ProcessConCtrlData.pHead->pPrev = NULL;
293 ProcessConCtrlData.pHead->flFlags = ODIN32_CONCTRL_FLAGS_INIT;
294 InitializeCriticalSection(&ProcessENVDB.section);
295
296 ProcessPDB.unknown10 = (PVOID)&unknownPDBData[0];
297 //initialize the startup info part of the db entry.
298 O32_GetStartupInfo(&StartupInfo);
299 StartupInfo.cb = sizeof(StartupInfo);
300 /* Set some defaults as GetStartupInfo() used to set... */
301 if (!(StartupInfo.dwFlags & STARTF_USESHOWWINDOW))
302 StartupInfo.wShowWindow= SW_NORMAL;
303 /* must be NULL for VC runtime */
304 StartupInfo.lpReserved = NULL;
305 StartupInfo.cbReserved2 = NULL;
306 if (!StartupInfo.lpDesktop)
307 StartupInfo.lpDesktop = (LPSTR)"Desktop";
308 if (!StartupInfo.lpTitle)
309 StartupInfo.lpTitle = (LPSTR)"Title";
310 ProcessENVDB.hStdin = StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
311 ProcessENVDB.hStdout = StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
312 ProcessENVDB.hStderr = StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
313
314 return teb;
315}
316//******************************************************************************
317// Set up the TEB structure of the CURRENT (!) thread
318//******************************************************************************
319BOOL WIN32API InitializeThread(TEB *winteb, BOOL fMainThread)
320{
321 //store TEB address in thread locale memory for easy retrieval
322 *TIBFlatPtr = (DWORD)winteb;
323
324//// winteb->exit_code = 0x103; /* STILL_ACTIVE */
325
326 winteb->stack_top = (PVOID)OSLibGetTIB(TIB_STACKTOP); /* 04 Top of thread stack */
327 winteb->stack_top = (PVOID)(((ULONG)winteb->stack_top + 0xFFF) & ~0xFFF);
328 //round to next page (OS/2 doesn't return a nice rounded value)
329 winteb->stack_low = (PVOID)OSLibGetTIB(TIB_STACKLOW); /* 08 Stack low-water mark */
330 //round to page boundary (OS/2 doesn't return a nice rounded value)
331 winteb->stack_low = (PVOID)((ULONG)winteb->stack_low & ~0xFFF);
332
333 winteb->o.odin.OrgTIBSel = GetFS();
334 winteb->o.odin.pWsockData = NULL;
335#ifdef DEBUG
336 winteb->o.odin.dbgCallDepth = 0;
337#endif
338 winteb->o.odin.pMessageBuffer = NULL;
339 winteb->o.odin.lcid = GetUserDefaultLCID();
340
341 if(OSLibGetPIB(PIB_TASKTYPE) == TASKTYPE_PM)
342 {
343 winteb->flags = 0; //todo gui
344 }
345 else winteb->flags = 0; //todo textmode
346
347 //Initialize thread security objects (TODO: Not complete)
348 SID_IDENTIFIER_AUTHORITY sidIdAuth = {0};
349 winteb->o.odin.threadinfo.dwType = SECTYPE_PROCESS | SECTYPE_INITIALIZED;
350
351 RtlAllocateAndInitializeSid(&sidIdAuth, 1, 0, 0, 0, 0, 0, 0, 0, 0, &winteb->o.odin.threadinfo.SidUser.User.Sid);
352
353 winteb->o.odin.threadinfo.SidUser.User.Attributes = 0; //?????????
354
355 winteb->o.odin.threadinfo.pTokenGroups = (TOKEN_GROUPS*)malloc(sizeof(TOKEN_GROUPS));
356 winteb->o.odin.threadinfo.pTokenGroups->GroupCount = 1;
357
358 RtlAllocateAndInitializeSid(&sidIdAuth, 1, 0, 0, 0, 0, 0, 0, 0, 0, &winteb->o.odin.threadinfo.PrimaryGroup.PrimaryGroup);
359
360 winteb->o.odin.threadinfo.pTokenGroups->Groups[0].Sid = winteb->o.odin.threadinfo.PrimaryGroup.PrimaryGroup;
361 winteb->o.odin.threadinfo.pTokenGroups->Groups[0].Attributes = 0; //????
362// pPrivilegeSet = NULL;
363// pTokenPrivileges= NULL;
364// TokenOwner = {0};
365// DefaultDACL = {0};
366// TokenSource = {0};
367 winteb->o.odin.threadinfo.TokenType = TokenPrimary;
368
369 dprintf(("InitializeTIB setup TEB with selector %x", winteb->teb_sel));
370 dprintf(("InitializeTIB: FS(%x):[0] = %x", GetFS(), QueryExceptionChain()));
371 return TRUE;
372}
373//******************************************************************************
374// Destroy the TIB selector and memory for the current thread
375//******************************************************************************
376void WIN32API DestroyTEB(TEB *winteb)
377{
378 SHORT orgtibsel;
379
380 dprintf(("DestroyTIB: FS = %x", GetFS()));
381 dprintf(("DestroyTIB: FS:[0] = %x", QueryExceptionChain()));
382
383 orgtibsel = winteb->o.odin.OrgTIBSel;
384
385 dprintf(("DestroyTIB: OSLibFreeSel %x", winteb->teb_sel));
386
387 threadListMutex.enter();
388 TEB *curteb = threadList;
389 if(curteb == winteb) {
390 threadList = winteb->o.odin.next;
391 }
392 else {
393 while(curteb->o.odin.next != winteb) {
394 curteb = curteb->o.odin.next;
395 if(curteb == NULL) {
396 dprintf(("DestroyTIB: couldn't find teb %x", winteb));
397 DebugInt3();
398 break;
399 }
400 }
401 if(curteb) {
402 curteb->o.odin.next = winteb->o.odin.next;
403 }
404 }
405 threadListMutex.leave();
406
407 // free allocated memory for security structures
408 free( winteb->o.odin.threadinfo.pTokenGroups );
409
410 // free PostMessage event semaphore
411 if(winteb->o.odin.hPostMsgEvent) {
412 CloseHandle(winteb->o.odin.hPostMsgEvent);
413 }
414
415 // free shared memory for WM_COPYDATA
416 if (winteb->o.odin.pWM_COPYDATA)
417 {
418 dprintf(("DestroyTEB: freeing WM_COPYDATA: %#p", winteb->o.odin.pWM_COPYDATA));
419 _sfree(winteb->o.odin.pWM_COPYDATA);
420 }
421
422#ifdef DEBUG
423 if (winteb->o.odin.arrstrCallStack != NULL)
424 free( winteb->o.odin.arrstrCallStack );
425#endif
426
427 //Restore our original FS selector
428 SetFS(orgtibsel);
429
430 //And free our own
431 OSLibFreeSel(winteb->teb_sel);
432
433 *TIBFlatPtr = 0;
434
435 dprintf(("DestroyTIB: FS(%x):[0] = %x", GetFS(), QueryExceptionChain()));
436 return;
437}
438//******************************************************************************
439//******************************************************************************
440ULONG WIN32API GetProcessTIBSel()
441{
442 if(fExitProcess) {
443 return 0;
444 }
445 return ProcessTIBSel;
446}
447/******************************************************************************/
448/******************************************************************************/
449void SetPDBInstance(HINSTANCE hInstance)
450{
451 ProcessPDB.hInstance = hInstance;
452}
453/******************************************************************************/
454/******************************************************************************/
455void WIN32API RestoreOS2TIB()
456{
457 SHORT orgtibsel;
458 TEB *winteb;
459
460 //If we're running an Odin32 OS/2 application (not converted!), then we
461 //we don't switch FS selectors
462 if(!fSwitchTIBSel) {
463 return;
464 }
465
466 winteb = (TEB *)*TIBFlatPtr;
467 if(winteb) {
468 orgtibsel = winteb->o.odin.OrgTIBSel;
469
470 //Restore our original FS selector
471 SetFS(orgtibsel);
472 }
473}
474/******************************************************************************/
475//Switch to WIN32 TIB (FS selector)
476//NOTE: This is not done for Odin32 applications (LX), unless
477// fForceSwitch is TRUE)
478/******************************************************************************/
479USHORT WIN32API SetWin32TIB(BOOL fForceSwitch)
480{
481 SHORT win32tibsel;
482 TEB *winteb;
483
484 //If we're running an Odin32 OS/2 application (not converted!), then we
485 //we don't switch FS selectors
486 if(!fSwitchTIBSel && !fForceSwitch) {
487 return GetFS();
488 }
489
490 winteb = (TEB *)*TIBFlatPtr;
491 if(winteb) {
492 win32tibsel = winteb->teb_sel;
493
494 //Restore our win32 FS selector
495 return SetReturnFS(win32tibsel);
496 }
497 else {
498 return GetFS();
499 }
500 // nested calls are OK, OS2ToWinCallback for instance
501 //else DebugInt3();
502
503 return GetFS();
504}
505//******************************************************************************
506// ODIN_SetTIBSwitch: override TIB switching
507//
508// Parameters:
509// BOOL fSwitchTIB
510// FALSE -> no TIB selector switching
511// TRUE -> force TIB selector switching
512//
513//******************************************************************************
514void WIN32API ODIN_SetTIBSwitch(BOOL fSwitchTIB)
515{
516 dprintf(("ODIN_SetTIBSwitch %d", fSwitchTIB));
517 if (!fForceWin32TIB) {
518 fSwitchTIBSel = fSwitchTIB;
519 if(fSwitchTIBSel) {
520 SetWin32TIB();
521 }
522 else RestoreOS2TIB();
523 } else {
524 dprintf(("ODIN_SetTIBSwitch: ignored due to fForceWin32TIB = TRUE"));
525 }
526}
527//******************************************************************************
528//******************************************************************************
529//#define DEBUG_HEAPSTATE
530#ifdef DEBUG_HEAPSTATE
531char *pszHeapDump = NULL;
532char *pszHeapDumpStart = NULL;
533
534int _LNK_CONV callback_function(const void *pentry, size_t sz, int useflag, int status,
535 const char *filename, size_t line)
536{
537 if (_HEAPOK != status) {
538// dprintf(("status is not _HEAPOK."));
539 return 1;
540 }
541 if (_USEDENTRY == useflag && sz && filename && line && pszHeapDump) {
542 sprintf(pszHeapDump, "allocated %08x %u at %s %d\n", pentry, sz, filename, line);
543 pszHeapDump += strlen(pszHeapDump);
544 }
545
546 return 0;
547}
548//******************************************************************************
549//******************************************************************************
550#endif
551VOID WIN32API ExitProcess(DWORD exitcode)
552{
553 HANDLE hThread = GetCurrentThread();
554 TEB *teb;
555
556 dprintf(("KERNEL32: ExitProcess %d (time %x)", exitcode, GetCurrentTime()));
557 dprintf(("KERNEL32: ExitProcess FS = %x\n", GetFS()));
558
559 // make sure the Win32 exception stack (if there is still any) is unwound
560 // before we destroy internal structures including the Win32 TIB
561 RtlUnwind(NULL, 0, 0, 0);
562
563 fExitProcess = TRUE;
564
565 // Lower priority of all threads to minimize the chance that they're scheduled
566 // during ExitProcess. Can't kill them as that's possibly dangerous (deadlocks
567 // in WGSS for instance)
568 threadListMutex.enter();
569 teb = threadList;
570 while(teb) {
571 if(teb->o.odin.hThread != hThread) {
572 dprintf(("Active thread id %d, handle %x", LOWORD(teb->o.odin.threadId), teb->o.odin.hThread));
573 SetThreadPriority(teb->o.odin.hThread, THREAD_PRIORITY_LOWEST);
574 }
575 teb = teb->o.odin.next;
576 }
577 threadListMutex.leave();
578
579 HMDeviceCommClass::CloseOverlappedIOHandlers();
580
581 //detach all dlls (LIFO order) before really unloading them; this
582 //should take care of circular dependencies (crash while accessing
583 //memory of a dll that has just been freed)
584 dprintf(("********************************************"));
585 dprintf(("**** Detach process from all dlls -- START"));
586 Win32DllBase::detachProcessFromAllDlls();
587 dprintf(("**** Detach process from all dlls -- END"));
588 dprintf(("********************************************"));
589
590 if(WinExe) {
591 delete(WinExe);
592 WinExe = NULL;
593 }
594
595 //Note: Needs to be done after deleting WinExe (destruction of exe + dll objects)
596 //Flush and delete all open memory mapped files
597 Win32MemMap::deleteAll();
598
599 //SvL: We must make sure no threads are still suspended (with SuspendThread)
600 // OS/2 seems to be unable to terminate the process otherwise (exitlist hang)
601 threadListMutex.enter();
602 teb = threadList;
603 while(teb) {
604 dprintf(("Active thread id %d, handle %x", LOWORD(teb->o.odin.threadId), teb->o.odin.hThread));
605 if(teb->o.odin.hThread != hThread) {
606 if(teb->o.odin.dwSuspend > 0) {
607 //kill any threads that are suspended; dangerous, but so is calling
608 //SuspendThread; we assume the app knew what it was doing
609 TerminateThread(teb->o.odin.hThread, 0);
610 ResumeThread(teb->o.odin.hThread);
611 }
612 else SetThreadPriority(teb->o.odin.hThread, THREAD_PRIORITY_LOWEST);
613 }
614 teb = teb->o.odin.next;
615 }
616 threadListMutex.leave();
617
618#ifdef DEBUG_HEAPSTATE
619 pszHeapDumpStart = pszHeapDump = (char *)malloc(10*1024*1024);
620 _heap_walk(callback_function);
621 dprintf((pszHeapDumpStart));
622 free(pszHeapDumpStart);
623#endif
624
625#ifdef PROFILE
626 // Note: after this point we do not expect any more Win32-API calls,
627 // so this is probably the best time to dump the gathered profiling
628 // information
629 PerfView_Write();
630 ProfilerWrite();
631 ProfilerTerminate();
632#endif /* PROFILE */
633
634 //Restore original OS/2 TIB selector
635 teb = GetThreadTEB();
636 if(teb) DestroyTEB(teb);
637
638 //avoid crashes since win32 & OS/2 exception handler aren't identical
639 //(terminate process generates two exceptions)
640 /* @@@PH 1998/02/12 Added Console Support */
641 if (iConsoleIsActive())
642 iConsoleWaitClose();
643
644 dprintf(("KERNEL32: ExitProcess done (time %x)", GetCurrentTime()));
645#ifndef DEBUG
646 OSLibDisablePopups();
647#endif
648 O32_ExitProcess(exitcode);
649}
650//******************************************************************************
651//******************************************************************************
652BOOL WIN32API FreeLibrary(HINSTANCE hinstance)
653{
654 Win32DllBase *winmod;
655 BOOL rc;
656
657 SetLastError(ERROR_SUCCESS);
658 //Ignore FreeLibary for executable
659 if(WinExe && hinstance == WinExe->getInstanceHandle()) {
660 return TRUE;
661 }
662
663 winmod = Win32DllBase::findModule(hinstance);
664 if(winmod) {
665 dprintf(("FreeLibrary %s", winmod->getName()));
666 //Only free it when the nrDynamicLibRef != 0
667 //This prevent problems after ExitProcess:
668 //i.e. dll A is referenced by our exe and loaded with LoadLibrary by dll B
669 // During ExitProcess it's unloaded once (before dll B), dll B calls
670 // FreeLibrary, but our exe also has a reference -> unloaded too many times
671 if(winmod->isDynamicLib()) {
672 winmod->decDynamicLib();
673 winmod->Release();
674 }
675 else {
676 dprintf(("Skipping dynamic unload as nrDynamicLibRef == 0"));
677 }
678 return(TRUE);
679 }
680 dprintf(("WARNING: KERNEL32: FreeLibrary %s %x NOT FOUND!", OSLibGetDllName(hinstance), hinstance));
681 return(TRUE);
682}
683/*****************************************************************************
684 * Name : VOID WIN32API FreeLibraryAndExitThread
685 * Purpose : The FreeLibraryAndExitThread function decrements the reference
686 * count of a loaded dynamic-link library (DLL) by one, and then
687 * calls ExitThread to terminate the calling thread.
688 * The function does not return.
689 *
690 * The FreeLibraryAndExitThread function gives threads that are
691 * created and executed within a dynamic-link library an opportunity
692 * to safely unload the DLL and terminate themselves.
693 * Parameters:
694 * Variables :
695 * Result :
696 * Remark :
697 *****************************************************************************/
698VOID WIN32API FreeLibraryAndExitThread( HMODULE hLibModule, DWORD dwExitCode)
699{
700
701 dprintf(("KERNEL32: FreeLibraryAndExitThread(%08x,%08x)", hLibModule, dwExitCode));
702 FreeLibrary(hLibModule);
703 ExitThread(dwExitCode);
704}
705/******************************************************************************/
706/******************************************************************************/
707/**
708 * LoadLibraryA can be used to map a DLL module into the calling process's
709 * addressspace. It returns a handle that can be used with GetProcAddress to
710 * get addresses of exported entry points (functions and variables).
711 *
712 * LoadLibraryA can also be used to map executable (.exe) modules into the
713 * address to access resources in the module. However, LoadLibrary can't be
714 * used to run an executable (.exe) module.
715 *
716 * @returns Handle to the library which was loaded.
717 * @param lpszLibFile Pointer to zero ASCII string giving the name of the
718 * executable image (either a Dll or an Exe) which is to be
719 * loaded.
720 *
721 * If no extention is specified the default .DLL extention is
722 * appended to the name. End the filename with an '.' if the
723 * file does not have an extention (and don't want the .DLL
724 * appended).
725 *
726 * If no path is specified, this API will use the Odin32
727 * standard search strategy to find the file. This strategy
728 * is described in the method Win32ImageBase::findDLL.
729 *
730 * This API likes to have backslashes (\), but will probably
731 * accept forward slashes too. Win32 SDK docs says that it
732 * should not contain forward slashes.
733 *
734 * Win32 SDK docs adds:
735 * "The name specified is the file name of the module and
736 * is not related to the name stored in the library module
737 * itself, as specified by the LIBRARY keyword in the
738 * module-definition (.def) file."
739 *
740 * @sketch Call LoadLibraryExA with flags set to 0.
741 * @status Odin32 Completely Implemented.
742 * @author Sander van Leeuwen (sandervl@xs4all.nl)
743 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
744 * @remark Forwards to LoadLibraryExA.
745 */
746HINSTANCE WIN32API LoadLibraryA(LPCTSTR lpszLibFile)
747{
748 HINSTANCE hDll;
749
750 dprintf(("KERNEL32: LoadLibraryA(%s) --> LoadLibraryExA(lpszLibFile, 0, 0)",
751 lpszLibFile));
752 hDll = LoadLibraryExA(lpszLibFile, 0, 0);
753 dprintf(("KERNEL32: LoadLibraryA(%s) returns 0x%x",
754 lpszLibFile, hDll));
755 return hDll;
756}
757
758
759/**
760 * LoadLibraryW can be used to map a DLL module into the calling process's
761 * addressspace. It returns a handle that can be used with GetProcAddress to
762 * get addresses of exported entry points (functions and variables).
763 *
764 * LoadLibraryW can also be used to map executable (.exe) modules into the
765 * address to access resources in the module. However, LoadLibrary can't be
766 * used to run an executable (.exe) module.
767 *
768 * @returns Handle to the library which was loaded.
769 * @param lpszLibFile Pointer to Unicode string giving the name of
770 * the executable image (either a Dll or an Exe) which is to
771 * be loaded.
772 *
773 * If no extention is specified the default .DLL extention is
774 * appended to the name. End the filename with an '.' if the
775 * file does not have an extention (and don't want the .DLL
776 * appended).
777 *
778 * If no path is specified, this API will use the Odin32
779 * standard search strategy to find the file. This strategy
780 * is described in the method Win32ImageBase::findDLL.
781 *
782 * This API likes to have backslashes (\), but will probably
783 * accept forward slashes too. Win32 SDK docs says that it
784 * should not contain forward slashes.
785 *
786 * Win32 SDK docs adds:
787 * "The name specified is the file name of the module and
788 * is not related to the name stored in the library module
789 * itself, as specified by the LIBRARY keyword in the
790 * module-definition (.def) file."
791 *
792 * @sketch Convert Unicode name to ascii.
793 * Call LoadLibraryExA with flags set to 0.
794 * free ascii string.
795 * @status Odin32 Completely Implemented.
796 * @author Sander van Leeuwen (sandervl@xs4all.nl)
797 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
798 * @remark Forwards to LoadLibraryExA.
799 */
800HINSTANCE WIN32API LoadLibraryW(LPCWSTR lpszLibFile)
801{
802 char * pszAsciiLibFile;
803 HINSTANCE hDll;
804
805 pszAsciiLibFile = UnicodeToAsciiString(lpszLibFile);
806 dprintf(("KERNEL32: LoadLibraryW(%s) --> LoadLibraryExA(lpszLibFile, 0, 0)",
807 pszAsciiLibFile));
808 hDll = LoadLibraryExA(pszAsciiLibFile, NULL, 0);
809 dprintf(("KERNEL32: LoadLibraryW(%s) returns 0x%x",
810 pszAsciiLibFile, hDll));
811 FreeAsciiString(pszAsciiLibFile);
812
813 return hDll;
814}
815
816//******************************************************************************
817//Custom build function to disable loading of LX dlls
818static BOOL fDisableLXDllLoading = FALSE;
819//******************************************************************************
820void WIN32API ODIN_DisableLXDllLoading()
821{
822 fDisableLXDllLoading = TRUE;
823}
824
825
826/**
827 * Custombuild API for registering a callback for LX Dll loading thru LoadLibrary*().
828 * @returns Success indicator.
829 * @param pfn Pointer to callback.
830 * NULL if callback is deregistered.
831 */
832BOOL WIN32API ODIN_SetLxDllLoadCallback(PFNLXDLLLOAD pfn)
833{
834 pfnLxDllLoadCallback = pfn;
835 return TRUE;
836}
837
838
839/**
840 * LoadLibraryExA can be used to map a DLL module into the calling process's
841 * addressspace. It returns a handle that can be used with GetProcAddress to
842 * get addresses of exported entry points (functions and variables).
843 *
844 * LoadLibraryExA can also be used to map executable (.exe) modules into the
845 * address to access resources in the module. However, LoadLibrary can't be
846 * used to run an executable (.exe) module.
847 *
848 * @returns Handle to the library which was loaded.
849 * @param lpszLibFile Pointer to Unicode string giving the name of
850 * the executable image (either a Dll or an Exe) which is to
851 * be loaded.
852 *
853 * If no extention is specified the default .DLL extention is
854 * appended to the name. End the filename with an '.' if the
855 * file does not have an extention (and don't want the .DLL
856 * appended).
857 *
858 * If no path is specified, this API will use the Odin32
859 * standard search strategy to find the file. This strategy
860 * is described in the method Win32ImageBase::findDLL.
861 * This may be alterned by the LOAD_WITH_ALTERED_SEARCH_PATH
862 * flag, see below.
863 *
864 * This API likes to have backslashes (\), but will probably
865 * accept forward slashes too. Win32 SDK docs says that it
866 * should not contain forward slashes.
867 *
868 * Win32 SDK docs adds:
869 * "The name specified is the file name of the module and
870 * is not related to the name stored in the library module
871 * itself, as specified by the LIBRARY keyword in the
872 * module-definition (.def) file."
873 *
874 * @param hFile Reserved. Must be 0.
875 *
876 * @param dwFlags Flags which specifies the taken when loading the module.
877 * The value 0 makes it identical to LoadLibraryA/W.
878 *
879 * Flags:
880 *
881 * DONT_RESOLVE_DLL_REFERENCES
882 * (WinNT/2K feature): Don't load imported modules and
883 * hence don't resolve imported symbols.
884 * DllMain isn't called either. (Which is obvious since
885 * it may use one of the importe symbols.)
886 *
887 * On the other hand, if this flag is NOT set, the system
888 * load imported modules, resolves imported symbols, calls
889 * DllMain for process and thread init and term (if wished
890 * by the module).
891 *
892 *
893 * LOAD_LIBRARY_AS_DATAFILE
894 * If this flag is set, the module is mapped into the
895 * address space but is not prepared for execution. Though
896 * it's preparted for resource API. Hence, you'll use this
897 * flag when you want to load a DLL for extracting
898 * messages or resources from it.
899 *
900 * The resulting handle can be used with any Odin32 API
901 * which operates on resources.
902 * (WinNt/2k supports all resource APIs while Win9x don't
903 * support the specialized resource APIs: LoadBitmap,
904 * LoadCursor, LoadIcon, LoadImage, LoadMenu.)
905 *
906 *
907 * LOAD_WITH_ALTERED_SEARCH_PATH
908 * If this flag is set and lpszLibFile specifies a path
909 * we'll use an alternative file search strategy to find
910 * imported modules. This stratgy is simply to use the
911 * path of the module being loaded instead of the path
912 * of the executable module as the first location
913 * to search for imported modules.
914 *
915 * If this flag is clear, the standard Odin32 standard
916 * search strategy. See Win32ImageBase::findDll for
917 * further information.
918 *
919 * not implemented yet.
920 *
921 * @status Open32 Partially Implemented.
922 * @author Sander van Leeuwen (sandervl@xs4all.nl)
923 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
924 * @remark Forwards to LoadLibraryExA.
925 */
926HINSTANCE WIN32API LoadLibraryExA(LPCTSTR lpszLibFile, HFILE hFile, DWORD dwFlags)
927{
928 HINSTANCE hDll;
929 Win32DllBase * pModule;
930 char szModname[CCHMAXPATH];
931 BOOL fPath; /* Flags which is set if the */
932 /* lpszLibFile contains a path. */
933 ULONG fPE; /* isPEImage return value. */
934 DWORD Characteristics; //file header's Characteristics
935 char *dot;
936
937 /** @sketch
938 * Some parameter validations is probably useful.
939 */
940 if (!VALID_PSZ(lpszLibFile))
941 {
942 dprintf(("KERNEL32: LoadLibraryExA(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
943 lpszLibFile, hFile, dwFlags, lpszLibFile));
944 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
945 return NULL;
946 }
947 if (!VALID_PSZMAXSIZE(lpszLibFile, CCHMAXPATH))
948 {
949 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): lpszLibFile string too long, %d\n",
950 lpszLibFile, hFile, dwFlags, strlen(lpszLibFile)));
951 SetLastError(ERROR_INVALID_PARAMETER);
952 return NULL;
953 }
954 if ((dwFlags & ~(DONT_RESOLVE_DLL_REFERENCES | LOAD_WITH_ALTERED_SEARCH_PATH | LOAD_LIBRARY_AS_DATAFILE)) != 0)
955 {
956 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): dwFlags have invalid or unsupported flags\n",
957 lpszLibFile, hFile, dwFlags));
958 SetLastError(ERROR_INVALID_PARAMETER);
959 return NULL;
960 }
961
962 /** @sketch
963 * First we'll see if the module is allready loaded - either as the EXE or as DLL.
964 * IF Executable present AND libfile matches the modname of the executable THEN
965 * RETURN instance handle of executable.
966 * Endif
967 * IF allready loaded THEN
968 * IF it's a LX dll which isn't loaded and we're using the PeLoader THEN
969 * Set Load library.
970 * Endif
971 * Inc dynamic reference count.
972 * Inc reference count.
973 * RETURN instance handle.
974 * Endif
975 */
976 strcpy(szModname, ODINHelperStripUNC((char*)lpszLibFile));
977 strupr(szModname);
978 dot = strchr(szModname, '.');
979 if(dot == NULL) {
980 //if there's no extension or trainling dot, we
981 //assume it's a dll (see Win32 SDK docs)
982 strcat(szModname, DLL_EXTENSION);
983 }
984 else {
985 if(dot[1] == 0) {
986 //a trailing dot means the module has no extension (SDK docs)
987 *dot = 0;
988 }
989 }
990 if (WinExe != NULL && WinExe->matchModName(szModname))
991 return WinExe->getInstanceHandle();
992
993 pModule = Win32DllBase::findModule((LPSTR)szModname);
994 if (pModule)
995 {
996 pModule->incDynamicLib();
997 pModule->AddRef();
998 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Dll found %s",
999 szModname, hFile, dwFlags, pModule->getInstanceHandle(), pModule->getFullPath()));
1000 return pModule->getInstanceHandle();
1001 }
1002
1003
1004 /** @sketch
1005 * Test if lpszLibFile has a path or not.
1006 * Copy the lpszLibFile to szModname, rename the dll and uppercase the name.
1007 * IF it hasn't a path THEN
1008 * Issue a findDll to find the dll/executable to be loaded.
1009 * IF the Dll isn't found THEN
1010 * Set last error and RETURN.
1011 * Endif.
1012 * Endif
1013 */
1014 fPath = strchr(szModname, '\\') || strchr(szModname, '/');
1015 Win32DllBase::renameDll(szModname);
1016
1017 if (!fPath)
1018 {
1019 char szModName2[CCHMAXPATH];
1020 strcpy(szModName2, szModname);
1021 if (!Win32ImageBase::findDll(szModName2, szModname, sizeof(szModname)))
1022 {
1023 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): module wasn't found. returns NULL",
1024 lpszLibFile, hFile, dwFlags));
1025 SetLastError(ERROR_FILE_NOT_FOUND);
1026 return NULL;
1027 }
1028 }
1029
1030 //test if dll is in PE or LX format
1031 fPE = Win32ImageBase::isPEImage(szModname, &Characteristics, NULL);
1032
1033 /** @sketch
1034 * IF (fDisableLXDllLoading && (!fPeLoader || fPE == failure)) THEN
1035 * Try load the executable using LoadLibrary
1036 * IF successfully loaded THEN
1037 * Try find registered/pe2lx object.
1038 * IF callback Then
1039 * If callback give green light Then
1040 * Find registered lx object.
1041 * Else
1042 * Unload it if loaded.
1043 * Endif
1044 * Endif
1045 * IF module object found Then
1046 * IF LX dll and is using the PE Loader THEN
1047 * Set Load library.
1048 * Inc reference count.
1049 * Endif
1050 * Inc dynamic reference count.
1051 * RETURN successfully.
1052 * Else
1053 * fail.
1054 * Endif
1055 * Endif
1056 * Endif
1057 */
1058 //only call OS/2 if LX binary or win32k process
1059 if (!fDisableLXDllLoading && (!fPeLoader || fPE != ERROR_SUCCESS))
1060 {
1061 hDll = OSLibDosLoadModule(szModname);
1062 if (hDll)
1063 {
1064 /* OS/2 dll, system dll, converted dll or win32k took care of it. */
1065 pModule = Win32DllBase::findModuleByOS2Handle(hDll);
1066 /* Custombuild customizing may take care of it too. */
1067 if (pfnLxDllLoadCallback)
1068 {
1069 /* If callback says yes, continue load it, else fail. */
1070 if (pfnLxDllLoadCallback(hDll, pModule ? pModule->getInstanceHandle() : NULL))
1071 pModule = Win32DllBase::findModuleByOS2Handle(hDll);
1072 else if (pModule)
1073 {
1074 pModule->Release();
1075 pModule = NULL;
1076 }
1077 }
1078 if (pModule)
1079 {
1080 if (pModule->isLxDll())
1081 {
1082 ((Win32LxDll *)pModule)->setDllHandleOS2(hDll);
1083 if (fPeLoader && pModule->AddRef() == -1)
1084 { //-1 -> load failed (attachProcess)
1085 delete pModule;
1086 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
1087 dprintf(("Dll %s refused to be loaded; aborting", szModname));
1088 return 0;
1089 }
1090
1091 }
1092 pModule->incDynamicLib();
1093 }
1094 else if (fExeStarted && !fIsOS2Image) {
1095 OSLibDosFreeModule(hDll);
1096 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
1097 dprintf(("Dll %s is not an Odin dll; unload & return failure", szModname));
1098 return 0;
1099 }
1100 else {
1101 /* bird 2001-07-10:
1102 * let's fail right away instead of hitting DebugInt3s and fail other places.
1103 * This is very annoying when running Opera on a debug build with netscape/2
1104 * plugins present. We'll make this conditional for the time being.
1105 */
1106 static BOOL fFailIfUnregisteredLX = -1;
1107 if (fFailIfUnregisteredLX == -1)
1108 fFailIfUnregisteredLX = getenv("ODIN32.FAIL_IF_UNREGISTEREDLX") != NULL;
1109 if (fExeStarted && fFailIfUnregisteredLX)
1110 {
1111 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Loaded OS/2 dll %s using DosLoadModule. returns NULL.",
1112 lpszLibFile, hFile, dwFlags, hDll, szModname));
1113 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
1114 return NULL;
1115 }
1116 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Loaded OS/2 dll %s using DosLoadModule.",
1117 lpszLibFile, hFile, dwFlags, hDll, szModname));
1118 return hDll; //happens when LoadLibrary is called in kernel32's initterm (nor harmful)
1119 }
1120 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Loaded %s using DosLoadModule.",
1121 lpszLibFile, hFile, dwFlags, hDll, szModname));
1122 return pModule->getInstanceHandle();
1123 }
1124 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): DosLoadModule (%s) failed. LastError=%d",
1125 lpszLibFile, hFile, dwFlags, szModname, GetLastError()));
1126 // YD return now for OS/2 dll only
1127 if (fPE != ERROR_SUCCESS)
1128 return NULL;
1129 }
1130 else
1131 hDll = NULL;
1132
1133
1134 /** @sketch
1135 * If PE image THEN
1136 * IF LOAD_LIBRARY_AS_DATAFILE or Executable THEN
1137 *
1138 *
1139 * Try load the file using the Win32PeLdrDll class.
1140 * <sketch continued further down>
1141 * Else
1142 * Set last error.
1143 * (hDll is NULL)
1144 * Endif
1145 * return hDll.
1146 */
1147 if(fPE == ERROR_SUCCESS)
1148 {
1149 Win32PeLdrDll *peldrDll;
1150
1151 //SvL: If executable -> load as data file (only resources)
1152 if(!(Characteristics & IMAGE_FILE_DLL))
1153 {
1154 dwFlags |= (LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES);
1155 }
1156
1157 peldrDll = new Win32PeLdrDll(szModname);
1158 if (peldrDll == NULL)
1159 {
1160 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Failed to created instance of Win32PeLdrDll. returns NULL.",
1161 lpszLibFile, hFile, dwFlags));
1162 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1163 return NULL;
1164 }
1165
1166 /** @sketch
1167 * Process dwFlags
1168 */
1169 if (dwFlags & LOAD_LIBRARY_AS_DATAFILE)
1170 {
1171 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): LOAD_LIBRARY_AS_DATAFILE",
1172 lpszLibFile, hFile, dwFlags));
1173 peldrDll->setLoadAsDataFile();
1174 peldrDll->disableLibraryCalls();
1175 }
1176 if (dwFlags & DONT_RESOLVE_DLL_REFERENCES)
1177 {
1178 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): DONT_RESOLVE_DLL_REFERENCES",
1179 lpszLibFile, hFile, dwFlags));
1180 peldrDll->disableLibraryCalls();
1181 peldrDll->disableImportHandling();
1182 }
1183 if (dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH)
1184 {
1185 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Warning dwFlags LOAD_WITH_ALTERED_SEARCH_PATH is not implemented.",
1186 lpszLibFile, hFile, dwFlags));
1187 //peldrDll->setLoadWithAlteredSearchPath();
1188 }
1189
1190 /** @sketch
1191 * Initiate the peldr DLL.
1192 * IF successful init THEN
1193 * Inc dynamic ref count.
1194 * Inc ref count.
1195 * Attach to process
1196 * IF successful THEN
1197 * hDLL <- instance handle.
1198 * ELSE
1199 * set last error
1200 * delete Win32PeLdrDll instance.
1201 * Endif
1202 * ELSE
1203 * set last error
1204 * delete Win32PeLdrDll instance.
1205 * Endif.
1206 */
1207 if(peldrDll->init(0) == LDRERROR_SUCCESS)
1208 {
1209 peldrDll->AddRef();
1210 if (peldrDll->attachProcess())
1211 {
1212 hDll = peldrDll->getInstanceHandle();
1213 //Must be called *after* attachprocess, since attachprocess may also
1214 //trigger LoadLibrary calls
1215 //Those dlls must not be put in front of this dll in the dynamic
1216 //dll list; or else the unload order is wrong:
1217 //i.e. RPAP3260 loads PNRS3260 in DLL_PROCESS_ATTACH
1218 // this means that in ExitProcess, PNRS3260 needs to be removed
1219 // first since RPAP3260 depends on it
1220 peldrDll->incDynamicLib();
1221 }
1222 else
1223 {
1224 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): attachProcess call to Win32PeLdrDll instance failed. returns NULL.",
1225 lpszLibFile, hFile, dwFlags));
1226 SetLastError(ERROR_DLL_INIT_FAILED);
1227 delete peldrDll;
1228 return NULL;
1229 }
1230 }
1231 else
1232 {
1233 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Failed to init Win32PeLdrDll instance. error=%d returns NULL.",
1234 lpszLibFile, hFile, dwFlags, peldrDll->getError()));
1235 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
1236 delete peldrDll;
1237 return NULL;
1238 }
1239 }
1240 else
1241 {
1242 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x) library wasn't found (%s) or isn't loadable; err %x",
1243 lpszLibFile, hFile, dwFlags, szModname, fPE));
1244 SetLastError(fPE);
1245 return NULL;
1246 }
1247
1248 return hDll;
1249}
1250
1251
1252/**
1253 * LoadLibraryExW can be used to map a DLL module into the calling process's
1254 * addressspace. It returns a handle that can be used with GetProcAddress to
1255 * get addresses of exported entry points (functions and variables).
1256 *
1257 * LoadLibraryExW can also be used to map executable (.exe) modules into the
1258 * address to access resources in the module. However, LoadLibrary can't be
1259 * used to run an executable (.exe) module.
1260 *
1261 * @returns Handle to the library which was loaded.
1262 * @param lpszLibFile Pointer to Unicode string giving the name of
1263 * the executable image (either a Dll or an Exe) which is to
1264 * be loaded.
1265 *
1266 * If no extention is specified the default .DLL extention is
1267 * appended to the name. End the filename with an '.' if the
1268 * file does not have an extention (and don't want the .DLL
1269 * appended).
1270 *
1271 * If no path is specified, this API will use the Odin32
1272 * standard search strategy to find the file. This strategy
1273 * is described in the method Win32ImageBase::findDLL.
1274 * This may be alterned by the LOAD_WITH_ALTERED_SEARCH_PATH
1275 * flag, see below.
1276 *
1277 * This API likes to have backslashes (\), but will probably
1278 * accept forward slashes too. Win32 SDK docs says that it
1279 * should not contain forward slashes.
1280 *
1281 * Win32 SDK docs adds:
1282 * "The name specified is the file name of the module and
1283 * is not related to the name stored in the library module
1284 * itself, as specified by the LIBRARY keyword in the
1285 * module-definition (.def) file."
1286 *
1287 * @param hFile Reserved. Must be 0.
1288 *
1289 * @param dwFlags Flags which specifies the taken when loading the module.
1290 * The value 0 makes it identical to LoadLibraryA/W.
1291 *
1292 * Flags:
1293 *
1294 * DONT_RESOLVE_DLL_REFERENCES
1295 * (WinNT/2K feature): Don't load imported modules and
1296 * hence don't resolve imported symbols.
1297 * DllMain isn't called either. (Which is obvious since
1298 * it may use one of the importe symbols.)
1299 *
1300 * On the other hand, if this flag is NOT set, the system
1301 * load imported modules, resolves imported symbols, calls
1302 * DllMain for process and thread init and term (if wished
1303 * by the module).
1304 *
1305 * LOAD_LIBRARY_AS_DATAFILE
1306 * If this flag is set, the module is mapped into the
1307 * address space but is not prepared for execution. Though
1308 * it's preparted for resource API. Hence, you'll use this
1309 * flag when you want to load a DLL for extracting
1310 * messages or resources from it.
1311 *
1312 * The resulting handle can be used with any Odin32 API
1313 * which operates on resources.
1314 * (WinNt/2k supports all resource APIs while Win9x don't
1315 * support the specialized resource APIs: LoadBitmap,
1316 * LoadCursor, LoadIcon, LoadImage, LoadMenu.)
1317 *
1318 * LOAD_WITH_ALTERED_SEARCH_PATH
1319 * If this flag is set and lpszLibFile specifies a path
1320 * we'll use an alternative file search strategy to find
1321 * imported modules. This stratgy is simply to use the
1322 * path of the module being loaded instead of the path
1323 * of the executable module as the first location
1324 * to search for imported modules.
1325 *
1326 * If this flag is clear, the standard Odin32 standard
1327 * search strategy. See Win32ImageBase::findDll for
1328 * further information.
1329 *
1330 * @sketch Convert Unicode name to ascii.
1331 * Call LoadLibraryExA.
1332 * Free ascii string.
1333 * return handle from LoadLibraryExA.
1334 * @status Open32 Partially Implemented.
1335 * @author Sander van Leeuwen (sandervl@xs4all.nl)
1336 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
1337 * @remark Forwards to LoadLibraryExA.
1338 */
1339HINSTANCE WIN32API LoadLibraryExW(LPCWSTR lpszLibFile, HFILE hFile, DWORD dwFlags)
1340{
1341 char * pszAsciiLibFile;
1342 HINSTANCE hDll;
1343
1344 pszAsciiLibFile = UnicodeToAsciiString(lpszLibFile);
1345 dprintf(("KERNEL32: LoadLibraryExW(%s, 0x%x, 0x%x) --> LoadLibraryExA",
1346 pszAsciiLibFile, hFile, dwFlags));
1347 hDll = LoadLibraryExA(pszAsciiLibFile, hFile, dwFlags);
1348 dprintf(("KERNEL32: LoadLibraryExW(%s, 0x%x, 0x%x) returns 0x%x",
1349 pszAsciiLibFile, hFile, dwFlags, hDll));
1350 FreeAsciiString(pszAsciiLibFile);
1351
1352 return hDll;
1353}
1354//******************************************************************************
1355//******************************************************************************
1356HINSTANCE16 WIN32API LoadLibrary16(LPCTSTR lpszLibFile)
1357{
1358 dprintf(("ERROR: LoadLibrary16 %s, not implemented", lpszLibFile));
1359 return 0;
1360}
1361//******************************************************************************
1362//******************************************************************************
1363VOID WIN32API FreeLibrary16(HINSTANCE16 hinstance)
1364{
1365 dprintf(("ERROR: FreeLibrary16 %x, not implemented", hinstance));
1366}
1367//******************************************************************************
1368//******************************************************************************
1369FARPROC WIN32API GetProcAddress16(HMODULE hModule, LPCSTR lpszProc)
1370{
1371 dprintf(("ERROR: GetProcAddress16 %x %x, not implemented", hModule, lpszProc));
1372 return 0;
1373}
1374
1375
1376/*************************************************************************
1377 * CommandLineToArgvW (re-exported as [SHELL32.7])
1378 */
1379/*************************************************************************
1380*
1381* We must interpret the quotes in the command line to rebuild the argv
1382* array correctly:
1383* - arguments are separated by spaces or tabs
1384* - quotes serve as optional argument delimiters
1385* '"a b"' -> 'a b'
1386* - escaped quotes must be converted back to '"'
1387* '\"' -> '"'
1388* - an odd number of '\'s followed by '"' correspond to half that number
1389* of '\' followed by a '"' (extension of the above)
1390* '\\\"' -> '\"'
1391* '\\\\\"' -> '\\"'
1392* - an even number of '\'s followed by a '"' correspond to half that number
1393* of '\', plus a regular quote serving as an argument delimiter (which
1394* means it does not appear in the result)
1395* 'a\\"b c"' -> 'a\b c'
1396* 'a\\\\"b c"' -> 'a\\b c'
1397* - '\' that are not followed by a '"' are copied literally
1398* 'a\b' -> 'a\b'
1399* 'a\\b' -> 'a\\b'
1400*
1401* Note:
1402* '\t' == 0x0009
1403* ' ' == 0x0020
1404* '"' == 0x0022
1405* '\\' == 0x005c
1406*/
1407LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
1408{
1409 DWORD argc;
1410 HGLOBAL hargv;
1411 LPWSTR *argv;
1412 LPCWSTR cs;
1413 LPWSTR arg,s,d;
1414 LPWSTR cmdline;
1415 int in_quotes,bcount;
1416
1417 if (*lpCmdline==0) {
1418 /* Return the path to the executable */
1419 DWORD size;
1420
1421 hargv=0;
1422 size=16;
1423 do {
1424 size*=2;
1425 hargv=GlobalReAlloc(hargv, size, 0);
1426 argv=(LPWSTR*)GlobalLock(hargv);
1427 } while (GetModuleFileNameW((HMODULE)0, (LPWSTR)(argv+1), size-sizeof(LPWSTR)) == 0);
1428 argv[0]=(LPWSTR)(argv+1);
1429 if (numargs)
1430 *numargs=2;
1431
1432 return argv;
1433 }
1434
1435 /* to get a writeable copy */
1436 argc=0;
1437 bcount=0;
1438 in_quotes=0;
1439 cs=lpCmdline;
1440 while (1) {
1441 if (*cs==0 || ((*cs==0x0009 || *cs==0x0020) && !in_quotes)) {
1442 /* space */
1443 argc++;
1444 /* skip the remaining spaces */
1445 while (*cs==0x0009 || *cs==0x0020) {
1446 cs++;
1447 }
1448 if (*cs==0)
1449 break;
1450 bcount=0;
1451 continue;
1452 } else if (*cs==0x005c) {
1453 /* '\', count them */
1454 bcount++;
1455 } else if ((*cs==0x0022) && ((bcount & 1)==0)) {
1456 /* unescaped '"' */
1457 in_quotes=!in_quotes;
1458 bcount=0;
1459 } else {
1460 /* a regular character */
1461 bcount=0;
1462 }
1463 cs++;
1464 }
1465 /* Allocate in a single lump, the string array, and the strings that go with it.
1466 * This way the caller can make a single GlobalFree call to free both, as per MSDN.
1467 */
1468 hargv=GlobalAlloc(0, argc*sizeof(LPWSTR)+(strlenW(lpCmdline)+1)*sizeof(WCHAR));
1469 argv=(LPWSTR*)GlobalLock(hargv);
1470 if (!argv)
1471 return NULL;
1472 cmdline=(LPWSTR)(argv+argc);
1473 strcpyW(cmdline, lpCmdline);
1474
1475 argc=0;
1476 bcount=0;
1477 in_quotes=0;
1478 arg=d=s=cmdline;
1479 while (*s) {
1480 if ((*s==0x0009 || *s==0x0020) && !in_quotes) {
1481 /* Close the argument and copy it */
1482 *d=0;
1483 argv[argc++]=arg;
1484
1485 /* skip the remaining spaces */
1486 do {
1487 s++;
1488 } while (*s==0x0009 || *s==0x0020);
1489
1490 /* Start with a new argument */
1491 arg=d=s;
1492 bcount=0;
1493 } else if (*s==0x005c) {
1494 /* '\\' */
1495 *d++=*s++;
1496 bcount++;
1497 } else if (*s==0x0022) {
1498 /* '"' */
1499 if ((bcount & 1)==0) {
1500 /* Preceeded by an even number of '\', this is half that
1501 * number of '\', plus a quote which we erase.
1502 */
1503 d-=bcount/2;
1504 in_quotes=!in_quotes;
1505 s++;
1506 } else {
1507 /* Preceeded by an odd number of '\', this is half that
1508 * number of '\' followed by a '"'
1509 */
1510 d=d-bcount/2-1;
1511 *d++='"';
1512 s++;
1513 }
1514 bcount=0;
1515 } else {
1516 /* a regular character */
1517 *d++=*s++;
1518 bcount=0;
1519 }
1520 }
1521 if (*arg) {
1522 *d='\0';
1523 argv[argc++]=arg;
1524 }
1525 if (numargs)
1526 *numargs=argc;
1527
1528 return argv;
1529}
1530
1531/**
1532 * Internal function which gets the commandline (string) used to start the current process.
1533 * @returns OS/2 / Windows return code
1534 * On successful return (NO_ERROR) the global variables
1535 * pszCmdLineA and pszCmdLineW are set.
1536 *
1537 * @param pszPeExe Pass in the name of the PE exe of this process. We'll
1538 * us this as exename and skip the first argument (ie. argv[1]).
1539 * If NULL we'll use the commandline from OS/2 as it is.
1540 * @status Completely implemented and tested.
1541 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1542 */
1543ULONG InitCommandLine(const char *pszPeExe)
1544{
1545 PCHAR pib_pchcmd; /* PIB pointer to commandline. */
1546 CHAR szFilename[CCHMAXPATH]; /* Filename buffer used to get the exe filename in. */
1547 ULONG cch; /* Commandline string length. (including terminator) */
1548 PSZ psz; /* Temporary string pointer. */
1549 PSZ psz2; /* Temporary string pointer. */
1550 APIRET rc; /* OS/2 return code. */
1551 BOOL fQuotes; /* Flag used to remember if the exe filename should be in quotes. */
1552 BOOL fKLIBC;
1553 LPWSTR *argvW;
1554 int i;
1555 ULONG cb;
1556
1557 /** @sketch
1558 * Get commandline from the PIB.
1559 */
1560 pib_pchcmd = (PCHAR)OSLibGetPIB(PIB_PCHCMD);
1561
1562 /** @sketch
1563 * Two methods of making the commandline:
1564 * (1) The first argument is skipped and the second is used as exe filname.
1565 * This applies to PE.EXE launched processes only.
1566 * (2) No skipping. First argument is the exe filename.
1567 * This applies to all but PE.EXE launched processes.
1568 *
1569 * Note: We could do some code size optimization here. Much of the code for
1570 * the two methods are nearly identical.
1571 *
1572 */
1573 if(pszPeExe)
1574 {
1575 /** @sketch
1576 * Allocate memory for the commandline.
1577 * Build commandline:
1578 * Copy exe filename.
1579 * Add arguments.
1580 */
1581 cch = strlen(pszPeExe)+1;
1582
1583 // PH 2002-04-11
1584 // Note: intentional memory leak, pszCmdLineW will not be freed
1585 // or allocated after process startup
1586 pszCmdLineA = psz = (PSZ)malloc(cch);
1587 if (psz == NULL)
1588 {
1589 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed\n", pszPeExe, cch));
1590 return ERROR_NOT_ENOUGH_MEMORY;
1591 }
1592 strcpy((char *)pszCmdLineA, pszPeExe);
1593
1594 rc = NO_ERROR;
1595 }
1596 else
1597 {
1598 /** @sketch Method (2):
1599 * First we'll have to determin the size of the commandline.
1600 *
1601 * As we don't assume that OS/2 allways puts a fully qualified EXE name
1602 * as the first string, we'll check if it's empty - and get the modulename
1603 * in that case - and allways get the fully qualified filename.
1604 */
1605 if (pib_pchcmd == NULL || pib_pchcmd[0] == '\0')
1606 {
1607 rc = OSLibDosQueryModuleName(OSLibGetPIB(PIB_HMTE), sizeof(szFilename), szFilename);
1608 if (rc != NO_ERROR)
1609 {
1610 dprintf(("KERNEL32: InitCommandLine(%p): OSLibQueryModuleName(0x%x,...) failed with rc=%d\n",
1611 pszPeExe, OSLibGetPIB(PIB_HMTE), rc));
1612 return rc;
1613 }
1614 }
1615 else
1616 {
1617 rc = OSLibDosQueryPathInfo(pib_pchcmd, FIL_QUERYFULLNAME, szFilename, sizeof(szFilename));
1618 if (rc != NO_ERROR)
1619 {
1620 dprintf(("KERNEL32: InitCommandLine(%p): (info) OSLibDosQueryPathInfo failed with rc=%d\n", pszPeExe, rc));
1621 strcpy(szFilename, pib_pchcmd);
1622 rc = NO_ERROR;
1623 }
1624 }
1625
1626 /** @sketch
1627 * We're still measuring the size of the commandline:
1628 * Check if we have to quote the exe filename.
1629 * Determin the length of the executable name including quotes and '\0'-terminator.
1630 * Count the length of the arguments. (We here count's all argument strings.)
1631 */
1632 fQuotes = strchr(szFilename, ' ') != NULL;
1633 cch = strlen(szFilename) + fQuotes*2 + 1;
1634 if (pib_pchcmd != NULL)
1635 {
1636 psz2 = pib_pchcmd + strlen(pib_pchcmd) + 1;
1637#ifdef __KLIBC__
1638 /* kLIBC spawn() detects if the process it starts is a kLIBC process
1639 * and uses special hidden command line arguments to pass additional
1640 * info to it which are then removed before passing arguments to
1641 * main(). Since we don't have global argc/argv pointers in kLIBC,
1642 * we can't access them here and have to cut out these hidden args
1643 * Yes, it's implementation dependent -- needs to be changed when
1644 * kLIBC 0.7 (which contains glibal argc/argv) comes out.
1645 */
1646 fKLIBC = strcmp(psz2, __KLIBC_ARG_SIGNATURE) == 0;
1647 if (fKLIBC)
1648 psz2 += strlen(psz2) + 1;
1649#else
1650 fKLIBC = FALSE;
1651#endif
1652 while (*psz2 != '\0')
1653 {
1654 /* if the first byte is a kLIBC flag, skip it */
1655 if (fKLIBC)
1656 psz2++;
1657 ULONG cchTmp = strlen(psz2);
1658 BOOL fArgQuotes = fKLIBC ? strchr(psz2, ' ') != NULL : FALSE;
1659 ULONG nSlashes = 0;
1660 if (fKLIBC)
1661 {
1662 /* calculate quotes to escape them with '\' */
1663 while (*psz2)
1664 if (*psz2++ == '"')
1665 ++nSlashes;
1666 ++psz2;
1667 }
1668 else
1669 {
1670 psz2 += cchTmp + 1;
1671 }
1672 cch += cchTmp + 1 /* space */ + (fArgQuotes ? 2 : 0) + nSlashes;
1673 }
1674 ++cch; /* terminating null */
1675 }
1676
1677 /** @sketch
1678 * Allocate memory for the commandline.
1679 * Build commandline:
1680 * Copy exe filename.
1681 * Add arguments.
1682 */
1683 pszCmdLineA = psz = (PSZ)malloc(cch);
1684 if (psz == NULL)
1685 {
1686 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed\n", pszPeExe, cch));
1687 return ERROR_NOT_ENOUGH_MEMORY;
1688 }
1689
1690 if (fQuotes)
1691 *psz++ = '"';
1692 strcpy(psz, szFilename);
1693 psz += strlen(psz);
1694 if (fQuotes)
1695 {
1696 *psz++ = '"';
1697 *psz = '\0';
1698 }
1699
1700 if (pib_pchcmd != NULL)
1701 {
1702 psz2 = pib_pchcmd + strlen(pib_pchcmd) + 1;
1703 /* See above */
1704 if (fKLIBC)
1705 psz2 += strlen(psz2) + 1;
1706 while (*psz2 != '\0')
1707 {
1708 /* if the first byte is a kLIBC flag, skip it */
1709 if (fKLIBC)
1710 psz2++;
1711 ULONG cchTmp = strlen(psz2);
1712 BOOL fArgQuotes = fKLIBC ? strchr(psz2, ' ') != NULL : FALSE;
1713 *psz++ = ' '; /* add space */
1714 if (fArgQuotes)
1715 *psz++ = '"';
1716 if (fKLIBC)
1717 {
1718 while (*psz2)
1719 {
1720 /* escape quotes with '\' */
1721 if (*psz2 == '"')
1722 *psz++ = '\\';
1723 *psz++ = *psz2++;
1724 }
1725 psz2++;
1726 }
1727 else
1728 {
1729 memcpy(psz, psz2, cchTmp);
1730 psz += cchTmp;
1731 psz2 += cchTmp + 1;
1732 }
1733 if (fArgQuotes)
1734 *psz++ = '"';
1735 }
1736 *psz = '\0';
1737 }
1738 }
1739
1740 /** @sketch
1741 * If successfully build ASCII commandline then convert it to UniCode.
1742 */
1743 if (rc == NO_ERROR)
1744 {
1745 // PH 2002-04-11
1746 // Note: intentional memory leak, pszCmdLineW will not be freed
1747 // or allocated after process startup
1748 cch = strlen(pszCmdLineA) + 1;
1749
1750 pszCmdLineW = (WCHAR*)malloc(cch * 2);
1751 if (pszCmdLineW != NULL) {
1752 //Translate from OS/2 to Windows codepage & ascii to unicode
1753 MultiByteToWideChar(CP_OEMCP, 0, pszCmdLineA, -1, (LPWSTR)pszCmdLineW, cch-1);
1754 ((LPWSTR)pszCmdLineW)[cch-1] = 0;
1755
1756 //ascii command line is still in OS/2 codepage, so convert it
1757 WideCharToMultiByte(CP_ACP, 0, pszCmdLineW, -1, (LPSTR)pszCmdLineA, cch-1, 0, NULL);
1758 ((LPSTR)pszCmdLineA)[cch-1] = 0;
1759
1760 // now, initialize __argcA and __argvA. These global variables are for the convenience
1761 // of applications that want to access the ANSI version of command line arguments w/o
1762 // using the lpCommandLine parameter of WinMain and parsing it manually
1763 LPWSTR *argvW = CommandLineToArgvW(pszCmdLineW, &__argcA);
1764 if (argvW != NULL)
1765 {
1766 // Allocate space for both the argument array and the arguments
1767 // Note: intentional memory leak, pszCmdLineW will not be freed
1768 // or allocated after process startup
1769 cb = sizeof(char*) * (__argcA + 1) + cch + __argcA;
1770 __argvA = (char **)malloc(cb);
1771 if (__argvA != NULL)
1772 {
1773 psz = ((char *)__argvA) + sizeof(char*) * __argcA;
1774 cb -= sizeof(char*) * __argcA;
1775 for (i = 0; i < __argcA; ++i)
1776 {
1777 cch = WideCharToMultiByte(CP_ACP, 0, argvW[i], -1, psz, cb, 0, NULL);
1778 if (!cch)
1779 {
1780 DebugInt3();
1781 dprintf(("KERNEL32: InitCommandLine(%p): WideCharToMultiByte() failed\n", pszPeExe));
1782 rc = ERROR_NOT_ENOUGH_MEMORY;
1783 break;
1784 }
1785 psz[cch++] = '\0';
1786 __argvA[i] = psz;
1787 psz += cch;
1788 cb -= cch;
1789 }
1790 // argv[argc] must be NULL
1791 __argvA[i] = NULL;
1792 }
1793 else
1794 {
1795 DebugInt3();
1796 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed (3)\n", pszPeExe, cch));
1797 rc = ERROR_NOT_ENOUGH_MEMORY;
1798 }
1799 }
1800 else
1801 {
1802 DebugInt3();
1803 dprintf(("KERNEL32: InitCommandLine(%p): CommandLineToArgvW() failed\n", pszPeExe));
1804 rc = ERROR_NOT_ENOUGH_MEMORY;
1805 }
1806 }
1807 else
1808 {
1809 DebugInt3();
1810 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed (2)\n", pszPeExe, cch * 2));
1811 rc = ERROR_NOT_ENOUGH_MEMORY;
1812 }
1813 }
1814
1815 return rc;
1816}
1817
1818/**
1819 * Gets the command line of the current process.
1820 * @returns On success:
1821 * Command line of the current process. One single string.
1822 * The first part of the command line string is the executable filename
1823 * of the current process. It might be in quotes if it contains spaces.
1824 * The rest of the string is arguments.
1825 *
1826 * On error:
1827 * NULL. Last error set. (does Win32 set last error this?)
1828 * @sketch IF not inited THEN
1829 * Init commandline assuming !PE.EXE
1830 * IF init failes THEN set last error.
1831 * ENDIF
1832 * return ASCII/ANSI commandline.
1833 * @status Completely implemented and tested.
1834 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1835 * @remark The Ring-3 PeLdr is resposible for calling InitCommandLine before anyone
1836 * is able to call this function.
1837 */
1838LPCSTR WIN32API GetCommandLineA(VOID)
1839{
1840 /*
1841 * Check if the commandline is initiated.
1842 * If not we'll have to do it.
1843 * ASSUMES that if not inited this isn't a PE.EXE lauched process.
1844 */
1845 if (pszCmdLineA == NULL)
1846 {
1847 APIRET rc;
1848 rc = InitCommandLine(NULL);
1849 if (rc != NULL)
1850 SetLastError(rc);
1851 }
1852
1853 dprintf(("KERNEL32: GetCommandLineA: %s\n", pszCmdLineA));
1854 return pszCmdLineA;
1855}
1856
1857
1858/**
1859 * Gets the command line of the current process.
1860 * @returns On success:
1861 * Command line of the current process. One single string.
1862 * The first part of the command line string is the executable filename
1863 * of the current process. It might be in quotes if it contains spaces.
1864 * The rest of the string is arguments.
1865 *
1866 * On error:
1867 * NULL. Last error set. (does Win32 set last error this?)
1868 * @sketch IF not inited THEN
1869 * Init commandline assuming !PE.EXE
1870 * IF init failes THEN set last error.
1871 * ENDIF
1872 * return Unicode commandline.
1873 * @status Completely implemented and tested.
1874 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1875 * @remark The Ring-3 PeLdr is resposible for calling InitCommandLine before anyone
1876 * is able to call this function.
1877 */
1878LPCWSTR WIN32API GetCommandLineW(void)
1879{
1880 /*
1881 * Check if the commandline is initiated.
1882 * If not we'll have to do it.
1883 * ASSUMES that if not inited this isn't a PE.EXE lauched process.
1884 */
1885 if (pszCmdLineW == NULL)
1886 {
1887 APIRET rc;
1888 rc = InitCommandLine(NULL);
1889 if (rc != NULL)
1890 SetLastError(rc);
1891 }
1892
1893 dprintf(("KERNEL32: GetCommandLineW: %ls\n", pszCmdLineW));
1894 return pszCmdLineW;
1895}
1896
1897
1898/**
1899 * GetModuleFileName gets the full path and file name for the specified module.
1900 * @returns Bytes written to the buffer (lpszPath). This count includes the
1901 * terminating '\0'.
1902 * On error 0 is returned. Last error is set.
1903 *
1904 * 2002-04-25 PH
1905 * Q - Do we set ERROR_BUFFER_OVERFLOW when cch > cchPath?
1906 * Q - Does NT really set the last error?
1907 * A > Win2k does not set LastError here, remains OK
1908 *
1909 * While GetModuleFileName does add a trailing termination zero
1910 * if there is enough room, the returned number of characters
1911 * *MUST NOT* include the zero character!
1912 * (Notes R6 Installer on Win2kSP6, verified Testcase)
1913 *
1914 * @param hModule Handle to the module you like to get the file name to.
1915 * @param lpszPath Output buffer for full path and file name.
1916 * @param cchPath Size of the lpszPath buffer.
1917 * @sketch Validate lpszPath.
1918 * Find the module object using handle.
1919 * If found Then
1920 * Get full path from module object.
1921 * If found path Then
1922 * Copy path to buffer and set the number of bytes written.
1923 * Else
1924 * IPE!
1925 * Else
1926 * Call Open32 GetModuleFileName. (kernel32 initterm needs/needed this)
1927 * Log result.
1928 * Return number of bytes written to the buffer.
1929 *
1930 * @status Completely implemented, Open32.
1931 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1932 * Sander van Leeuwen (sandervl@xs4all.nl)
1933 * Patrick Haller (patrick.haller@innotek.de)
1934 * @remark - Do we still have to call Open32?
1935 */
1936DWORD WIN32API GetModuleFileNameA(HMODULE hModule, LPTSTR lpszPath, DWORD cchPath)
1937{
1938 Win32ImageBase * pMod; /* Pointer to the module object. */
1939 DWORD cch = 0; /* Length of the */
1940
1941 // PH 2002-04-24 Note:
1942 // WIN2k just crashes in NTDLL if lpszPath is invalid!
1943 if (!VALID_PSZ(lpszPath))
1944 {
1945 dprintf(("KERNEL32: GetModuleFileNameA(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
1946 hModule, lpszPath, cchPath, lpszPath));
1947 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
1948 return 0;
1949 }
1950
1951 pMod = Win32ImageBase::findModule(hModule);
1952 if (pMod != NULL)
1953 {
1954 const char *pszFn = pMod->getFullPath();
1955 if (pszFn)
1956 {
1957 cch = strlen(pszFn);
1958 if (cch >= cchPath)
1959 cch = cchPath;
1960 else
1961 // if there is sufficient room for the zero termination,
1962 // write it additionally, uncounted
1963 lpszPath[cch] = '\0';
1964
1965 memcpy(lpszPath, pszFn, cch);
1966 }
1967 else
1968 {
1969 dprintf(("KERNEL32: GetModuleFileNameA(%x,...): IPE - getFullPath returned NULL or empty string\n"));
1970 DebugInt3();
1971 SetLastError(ERROR_INVALID_HANDLE);
1972 }
1973 }
1974 else
1975 {
1976 SetLastError(ERROR_INVALID_HANDLE);
1977 //only needed for call inside kernel32's initterm (profile init)
1978 //(console init only it seems...)
1979 cch = OSLibDosGetModuleFileName(hModule, lpszPath, cchPath);
1980 }
1981
1982 if (cch > 0)
1983 dprintf(("KERNEL32: GetModuleFileNameA(%x %x): %s %d\n", hModule, lpszPath, lpszPath, cch));
1984 else
1985 dprintf(("KERNEL32: WARNING: GetModuleFileNameA(%x,...) - not found!", hModule));
1986
1987 return cch;
1988}
1989
1990
1991/**
1992 * GetModuleFileName gets the full path and file name for the specified module.
1993 * @returns Bytes written to the buffer (lpszPath). This count includes the
1994 * terminating '\0'.
1995 * On error 0 is returned. Last error is set.
1996 * @param hModule Handle to the module you like to get the file name to.
1997 * @param lpszPath Output buffer for full path and file name.
1998 * @param cchPath Size of the lpszPath buffer.
1999 * @sketch Find the module object using handle.
2000 * If found Then
2001 * get full path from module object.
2002 * If found path Then
2003 * Determin path length.
2004 * Translate the path to into the buffer.
2005 * Else
2006 * IPE.
2007 * else
2008 * SetLastError to invalid handle.
2009 * Log result.
2010 * return number of bytes written to the buffer.
2011 *
2012 * @status Completely implemented.
2013 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
2014 * @remark - We do _NOT_ call Open32.
2015 * - Do we set ERROR_BUFFER_OVERFLOW when cch > cchPath?
2016 * - Does NT really set the last error?
2017 */
2018DWORD WIN32API GetModuleFileNameW(HMODULE hModule, LPWSTR lpszPath, DWORD cchPath)
2019{
2020 Win32ImageBase * pMod;
2021 DWORD cch = 0;
2022
2023 if (!VALID_PSZ(lpszPath))
2024 {
2025 dprintf(("KERNEL32: GetModuleFileNameW(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
2026 hModule, lpszPath, cchPath, lpszPath));
2027 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
2028 return 0;
2029 }
2030
2031 pMod = Win32ImageBase::findModule(hModule);
2032 if (pMod != NULL)
2033 {
2034 const char *pszFn = pMod->getFullPath();
2035 if (pszFn || *pszFn != '\0')
2036 {
2037 cch = strlen(pszFn) + 1;
2038 if (cch > cchPath)
2039 cch = cchPath;
2040 AsciiToUnicodeN(pszFn, lpszPath, cch);
2041 }
2042 else
2043 {
2044 dprintf(("KERNEL32: GetModuleFileNameW(%x,...): IPE - getFullPath returned NULL or empty string\n"));
2045 DebugInt3();
2046 SetLastError(ERROR_INVALID_HANDLE);
2047 }
2048 }
2049 else
2050 SetLastError(ERROR_INVALID_HANDLE);
2051
2052 if (cch > 0)
2053 dprintf(("KERNEL32: GetModuleFileNameW(%x,...): %s %d\n", hModule, lpszPath, cch));
2054 else
2055 dprintf(("KERNEL32: WARNING: GetModuleFileNameW(%x,...) - not found!", hModule));
2056
2057 return cch;
2058}
2059
2060
2061//******************************************************************************
2062//NOTE: GetModuleHandleA does NOT support files with multiple dots (i.e.
2063// very.weird.exe)
2064//
2065// hinst = LoadLibrary("WINSPOOL.DRV"); -> succeeds
2066// hinst2 = GetModuleHandle("WINSPOOL.DRV"); -> succeeds
2067// hinst3 = GetModuleHandle("WINSPOOL."); -> fails
2068// hinst4 = GetModuleHandle("WINSPOOL"); -> fails
2069// hinst = LoadLibrary("KERNEL32.DLL"); -> succeeds
2070// hinst2 = GetModuleHandle("KERNEL32.DLL"); -> succeeds
2071// hinst3 = GetModuleHandle("KERNEL32."); -> fails
2072// hinst4 = GetModuleHandle("KERNEL32"); -> succeeds
2073// Same behaviour as observed in NT4, SP6
2074//******************************************************************************
2075HANDLE WIN32API GetModuleHandleA(LPCTSTR lpszModule)
2076{
2077 HANDLE hMod = 0;
2078 Win32DllBase *windll;
2079 char szModule[CCHMAXPATH];
2080 char *dot;
2081
2082 if(lpszModule == NULL)
2083 {
2084 if(WinExe)
2085 hMod = WinExe->getInstanceHandle();
2086 else
2087 {
2088 // // Just fail this API
2089 // hMod = 0;
2090 // SetLastError(ERROR_INVALID_HANDLE);
2091 // Wrong: in an ODIN32-LX environment, just
2092 // assume a fake handle
2093 hMod = -1;
2094 }
2095 }
2096 else
2097 {
2098 strcpy(szModule, OSLibStripPath((char *)lpszModule));
2099 strupr(szModule);
2100 dot = strchr(szModule, '.');
2101 if(dot == NULL) {
2102 //if no extension -> add .DLL (see SDK docs)
2103 strcat(szModule, DLL_EXTENSION);
2104 }
2105 else {
2106 if(dot[1] == 0) {
2107 //a trailing dot means the module has no extension (SDK docs)
2108 *dot = 0;
2109 }
2110 }
2111 if(WinExe && WinExe->matchModName(szModule)) {
2112 hMod = WinExe->getInstanceHandle();
2113 }
2114 else {
2115 windll = Win32DllBase::findModule(szModule);
2116 if(windll) {
2117 hMod = windll->getInstanceHandle();
2118 }
2119 }
2120 }
2121 dprintf(("KERNEL32: GetModuleHandle %s returned %X\n", lpszModule, hMod));
2122 return(hMod);
2123}
2124//******************************************************************************
2125//******************************************************************************
2126HMODULE WIN32API GetModuleHandleW(LPCWSTR lpwszModuleName)
2127{
2128 HMODULE rc;
2129 char *astring = NULL;
2130
2131 if (NULL != lpwszModuleName)
2132 astring = UnicodeToAsciiString((LPWSTR)lpwszModuleName);
2133
2134 rc = GetModuleHandleA(astring);
2135 dprintf(("KERNEL32: OS2GetModuleHandleW %s returned %X\n", astring, rc));
2136
2137 if (NULL != astring)
2138 FreeAsciiString(astring);
2139
2140 return(rc);
2141}
2142//******************************************************************************
2143//Checks whether program is LX or PE
2144//******************************************************************************
2145BOOL WIN32API ODIN_IsWin32App(LPSTR lpszProgramPath)
2146{
2147 DWORD Characteristics;
2148
2149 return Win32ImageBase::isPEImage(lpszProgramPath, &Characteristics, NULL) == NO_ERROR;
2150}
2151//******************************************************************************
2152//******************************************************************************
2153static char szPECmdLoader[260] = "";
2154static char szPEGUILoader[260] = "";
2155static char szNELoader[260] = "";
2156//******************************************************************************
2157//Set default paths for PE & NE loaders
2158//******************************************************************************
2159BOOL InitLoaders()
2160{
2161 int len;
2162
2163 len = PROFILE_GetOdinIniString(ODINSYSTEM_SECTION, "PEC_EXE", "",
2164 szPECmdLoader, sizeof(szPECmdLoader));
2165 if (len == 0)
2166 sprintf(szPECmdLoader, "%s\\PEC.EXE", InternalGetSystemDirectoryA());
2167
2168 len = PROFILE_GetOdinIniString(ODINSYSTEM_SECTION, "PE_EXE", "",
2169 szPEGUILoader, sizeof(szPEGUILoader));
2170 if (len == 0)
2171 sprintf(szPEGUILoader, "%s\\PE.EXE", InternalGetSystemDirectoryA());
2172
2173
2174 len = PROFILE_GetOdinIniString(ODINSYSTEM_SECTION, "W16ODIN_EXE", "",
2175 szNELoader, sizeof(szNELoader));
2176 if (len == 0)
2177 sprintf(szNELoader, "%s\\W16ODIN.EXE", InternalGetSystemDirectoryA());
2178
2179 return TRUE;
2180}
2181//******************************************************************************
2182//Override loader names (PEC, PE, W16ODIN)
2183//******************************************************************************
2184BOOL WIN32API ODIN_SetLoaders(LPCSTR pszPECmdLoader, LPCSTR pszPEGUILoader,
2185 LPCSTR pszNELoader)
2186{
2187 if(pszPECmdLoader) dprintf(("PE Cmd %s", pszPECmdLoader));
2188 if(pszPEGUILoader) dprintf(("PE GUI %s", pszPEGUILoader));
2189 if(pszNELoader) dprintf(("NE %s", pszNELoader));
2190 if(pszPECmdLoader) strcpy(szPECmdLoader, pszPECmdLoader);
2191 if(pszPEGUILoader) strcpy(szPEGUILoader, pszPEGUILoader);
2192 if(pszNELoader) strcpy(szNELoader, pszNELoader);
2193
2194 return TRUE;
2195}
2196//******************************************************************************
2197//******************************************************************************
2198BOOL WIN32API ODIN_QueryLoaders(LPSTR pszPECmdLoader, INT cchPECmdLoader,
2199 LPSTR pszPEGUILoader, INT cchPEGUILoader,
2200 LPSTR pszNELoader, INT cchNELoader)
2201{
2202 if(pszPECmdLoader) strncpy(pszPECmdLoader, szPECmdLoader, cchPECmdLoader);
2203 if(pszPEGUILoader) strncpy(pszPEGUILoader, szPEGUILoader, cchPEGUILoader);
2204 if(pszNELoader) strncpy(pszNELoader, szNELoader, cchNELoader);
2205
2206 return TRUE;
2207}
2208//******************************************************************************
2209//******************************************************************************
2210static BOOL WINAPI O32_CreateProcessA(LPCSTR lpApplicationName, LPCSTR lpCommandLine,
2211 LPSECURITY_ATTRIBUTES lpProcessAttributes,
2212 LPSECURITY_ATTRIBUTES lpThreadAttributes,
2213 BOOL bInheritHandles, DWORD dwCreationFlags,
2214 LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
2215 LPSTARTUPINFOA lpStartupInfo,
2216 LPPROCESS_INFORMATION lpProcessInfo)
2217{
2218 dprintf(("KERNEL32: O32_CreateProcessA %s cline:%s inherit:%d cFlags:%x "
2219 "Env:%x CurDir:%s StartupFlags:%x\n",
2220 lpApplicationName, lpCommandLine, bInheritHandles, dwCreationFlags,
2221 lpEnvironment, lpCurrentDirectory, lpStartupInfo));
2222
2223 LPSTR lpstr;
2224 DWORD cb;
2225 BOOL rc;
2226
2227 #define ALLOC_OEM(v) \
2228 if (v) { \
2229 lpstr = (LPSTR)_smalloc(strlen(v) + 1); \
2230 CharToOemA(v, lpstr); \
2231 v = lpstr; \
2232 }
2233 #define FREE_OEM(v) \
2234 if (v) \
2235 _sfree((void*)v); \
2236
2237
2238 // this converts all string arguments from ANSI to OEM expected by
2239 // O32_CreateProcess()
2240
2241 ALLOC_OEM(lpApplicationName)
2242 ALLOC_OEM(lpCommandLine)
2243 ALLOC_OEM(lpCurrentDirectory)
2244
2245 if (lpEnvironment) {
2246 cb = 0;
2247 lpstr = (LPSTR)lpEnvironment;
2248 while (lpstr[cb]) {
2249 cb += strlen(&lpstr[cb]) + 1;
2250 }
2251 ++cb;
2252 lpstr = (LPSTR)_smalloc(cb);
2253 CharToOemBuffA((LPSTR)lpEnvironment, lpstr, cb);
2254 lpEnvironment = lpstr;
2255 }
2256
2257 ALLOC_OEM(lpStartupInfo->lpReserved)
2258 ALLOC_OEM(lpStartupInfo->lpDesktop)
2259 ALLOC_OEM(lpStartupInfo->lpTitle)
2260
2261 rc = O32_CreateProcess(lpApplicationName, lpCommandLine,
2262 lpProcessAttributes, lpThreadAttributes,
2263 bInheritHandles, dwCreationFlags,
2264 lpEnvironment, lpCurrentDirectory,
2265 lpStartupInfo, lpProcessInfo);
2266
2267 FREE_OEM(lpStartupInfo->lpTitle)
2268 FREE_OEM(lpStartupInfo->lpDesktop)
2269 FREE_OEM(lpStartupInfo->lpReserved)
2270
2271 FREE_OEM(lpEnvironment)
2272
2273 FREE_OEM(lpCurrentDirectory)
2274 FREE_OEM(lpCommandLine)
2275 FREE_OEM(lpApplicationName)
2276
2277 #undef FREE_OEM
2278 #undef ALLOC_OEM
2279
2280 return rc;
2281}
2282//******************************************************************************
2283//******************************************************************************
2284static void OSLibSetBeginLibpathA(char *lpszBeginlibpath)
2285{
2286 PSZ psz = NULL;
2287 if (lpszBeginlibpath) {
2288 psz = (PSZ)malloc(strlen(lpszBeginlibpath) + 1);
2289 CharToOemA(lpszBeginlibpath, psz);
2290 }
2291 OSLibSetBeginLibpath(psz);
2292 if (psz) {
2293 free(psz);
2294 }
2295}
2296//******************************************************************************
2297//******************************************************************************
2298static void OSLibQueryBeginLibpathA(char *lpszBeginlibpath, int size)
2299{
2300 OSLibQueryBeginLibpath(lpszBeginlibpath, size);
2301 OemToCharA(lpszBeginlibpath, lpszBeginlibpath);
2302}
2303//******************************************************************************
2304//******************************************************************************
2305BOOL WINAPI CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine,
2306 LPSECURITY_ATTRIBUTES lpProcessAttributes,
2307 LPSECURITY_ATTRIBUTES lpThreadAttributes,
2308 BOOL bInheritHandles, DWORD dwCreationFlags,
2309 LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
2310 LPSTARTUPINFOA lpStartupInfo,
2311 LPPROCESS_INFORMATION lpProcessInfo )
2312{
2313 STARTUPINFOA startinfo;
2314 TEB *pThreadDB = (TEB*)GetThreadTEB();
2315 char *cmdline = NULL, *newenv = NULL, *oldlibpath = NULL;
2316 BOOL rc;
2317 LPSTR lpstr;
2318
2319 dprintf(("KERNEL32: CreateProcessA %s cline:%s inherit:%d cFlags:%x Env:%x CurDir:%s StartupFlags:%x\n",
2320 lpApplicationName, lpCommandLine, bInheritHandles, dwCreationFlags,
2321 lpEnvironment, lpCurrentDirectory, lpStartupInfo));
2322
2323#ifdef DEBUG
2324 if(lpStartupInfo) {
2325 dprintf(("lpStartupInfo->lpReserved %x", lpStartupInfo->lpReserved));
2326 dprintf(("lpStartupInfo->lpDesktop %x", lpStartupInfo->lpDesktop));
2327 dprintf(("lpStartupInfo->lpTitle %s", lpStartupInfo->lpTitle));
2328 dprintf(("lpStartupInfo->dwX %x", lpStartupInfo->dwX));
2329 dprintf(("lpStartupInfo->dwY %x", lpStartupInfo->dwY));
2330 dprintf(("lpStartupInfo->dwXSize %x", lpStartupInfo->dwXSize));
2331 dprintf(("lpStartupInfo->dwYSize %x", lpStartupInfo->dwYSize));
2332 dprintf(("lpStartupInfo->dwXCountChars %x", lpStartupInfo->dwXCountChars));
2333 dprintf(("lpStartupInfo->dwYCountChars %x", lpStartupInfo->dwYCountChars));
2334 dprintf(("lpStartupInfo->dwFillAttribute %x", lpStartupInfo->dwFillAttribute));
2335 dprintf(("lpStartupInfo->dwFlags %x", lpStartupInfo->dwFlags));
2336 dprintf(("lpStartupInfo->wShowWindow %x", lpStartupInfo->wShowWindow));
2337 dprintf(("lpStartupInfo->hStdInput %x", lpStartupInfo->hStdInput));
2338 dprintf(("lpStartupInfo->hStdOutput %x", lpStartupInfo->hStdOutput));
2339 dprintf(("lpStartupInfo->hStdError %x", lpStartupInfo->hStdError));
2340 }
2341#endif
2342
2343 if(bInheritHandles && lpStartupInfo->dwFlags & STARTF_USESTDHANDLES)
2344 {
2345 //Translate standard handles if the child needs to inherit them
2346 int retcode = 0;
2347
2348 memcpy(&startinfo, lpStartupInfo, sizeof(startinfo));
2349 if(lpStartupInfo->hStdInput) {
2350 retcode |= HMHandleTranslateToOS2(lpStartupInfo->hStdInput, &startinfo.hStdInput);
2351 }
2352 if(lpStartupInfo->hStdOutput) {
2353 retcode |= HMHandleTranslateToOS2(lpStartupInfo->hStdOutput, &startinfo.hStdOutput);
2354 }
2355 if(lpStartupInfo->hStdError) {
2356 retcode |= HMHandleTranslateToOS2(lpStartupInfo->hStdError, &startinfo.hStdError);
2357 }
2358
2359 if(retcode) {
2360 SetLastError(ERROR_INVALID_HANDLE);
2361 rc = FALSE;
2362 goto finished;
2363 }
2364
2365 lpStartupInfo = &startinfo;
2366 }
2367
2368 if(lpApplicationName) {
2369 if(lpCommandLine) {
2370 //skip exe name in lpCommandLine
2371 //TODO: doesn't work for directories with spaces!
2372 while(*lpCommandLine != 0 && *lpCommandLine != ' ')
2373 lpCommandLine++;
2374
2375 if(*lpCommandLine != 0) {
2376 lpCommandLine++;
2377 }
2378 cmdline = (char *)malloc(strlen(lpApplicationName)+strlen(lpCommandLine) + 16);
2379 sprintf(cmdline, "%s %s", lpApplicationName, lpCommandLine);
2380 }
2381 else {
2382 cmdline = (char *)malloc(strlen(lpApplicationName) + 16);
2383 sprintf(cmdline, "%s", lpApplicationName);
2384 }
2385 }
2386 else {
2387 cmdline = (char *)malloc(strlen(lpCommandLine) + 16);
2388 sprintf(cmdline, "%s", lpCommandLine);
2389 }
2390
2391 char szAppName[MAX_PATH];
2392 char buffer[MAX_PATH];
2393 DWORD fileAttr;
2394 char *exename;
2395
2396 szAppName[0] = 0;
2397
2398 exename = buffer;
2399 strncpy(buffer, cmdline, sizeof(buffer));
2400 buffer[MAX_PATH-1] = 0;
2401 if(*exename == '"') {
2402 exename++;
2403 while(*exename != 0 && *exename != '"')
2404 exename++;
2405
2406 if(*exename != 0) {
2407 *exename = 0;
2408 }
2409 exename++;
2410 if (SearchPathA( NULL, &buffer[1], ".exe", sizeof(szAppName), szAppName, NULL ) ||
2411 SearchPathA( NULL, &buffer[1], NULL, sizeof(szAppName), szAppName, NULL ))
2412 {
2413 //
2414 }
2415 }
2416 else {
2417 BOOL fTerminate = FALSE;
2418 DWORD fileAttr;
2419
2420 while(*exename != 0) {
2421 while(*exename != 0 && *exename != ' ')
2422 exename++;
2423
2424 if(*exename != 0) {
2425 *exename = 0;
2426 fTerminate = TRUE;
2427 }
2428 dprintf(("Trying '%s'", buffer ));
2429 if (SearchPathA( NULL, buffer, ".exe", sizeof(szAppName), szAppName, NULL ) ||
2430 SearchPathA( NULL, buffer, NULL, sizeof(szAppName), szAppName, NULL ))
2431 {
2432 if(fTerminate) exename++;
2433 break;
2434 }
2435 else
2436 {//maybe it's a short name
2437 if(GetLongPathNameA(buffer, szAppName, sizeof(szAppName)))
2438 {
2439 if(fTerminate) exename++;
2440 break;
2441 }
2442 }
2443 if(fTerminate) {
2444 *exename = ' ';
2445 exename++;
2446 fTerminate = FALSE;
2447 }
2448 }
2449 }
2450 lpCommandLine = cmdline + (exename - buffer); //start of command line parameters
2451
2452 fileAttr = GetFileAttributesA(szAppName);
2453 if(fileAttr == -1 || (fileAttr & FILE_ATTRIBUTE_DIRECTORY)) {
2454 dprintf(("CreateProcess: can't find executable!"));
2455
2456 SetLastError(ERROR_FILE_NOT_FOUND);
2457
2458 rc = FALSE;
2459 goto finished;
2460 }
2461
2462 if(lpEnvironment) {
2463 char *envA = (char *)lpEnvironment;
2464 if(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT) {
2465 // process the CREATE_UNICODE_ENVIRONMENT on our own --
2466 // O32_CreateProcessA() is not aware of it
2467 dwCreationFlags &= ~CREATE_UNICODE_ENVIRONMENT;
2468
2469 WCHAR *tmp = (WCHAR *)lpEnvironment;
2470 int sizeW = 0;
2471 while (*tmp) {
2472 int lenW = lstrlenW(tmp);
2473 sizeW += lenW + 1;
2474 tmp += lenW + 1;
2475 }
2476 sizeW++; // terminating null
2477 int sizeA = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)lpEnvironment, sizeW,
2478 NULL, 0, 0, NULL);
2479 envA = (char *)malloc(sizeA);
2480 if(envA == NULL) {
2481 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2482 rc = FALSE;
2483 goto finished;
2484 }
2485 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)lpEnvironment, sizeW,
2486 envA, sizeA, 0, NULL);
2487 }
2488 newenv = CreateNewEnvironment(envA);
2489 if(envA != (char *)lpEnvironment)
2490 free(envA);
2491 if(newenv == NULL) {
2492 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2493 rc = FALSE;
2494 goto finished;
2495 }
2496 lpEnvironment = newenv;
2497 }
2498
2499 DWORD Characteristics, SubSystem, fNEExe, fPEExe;
2500
2501 fPEExe = Win32ImageBase::isPEImage(szAppName, &Characteristics, &SubSystem, &fNEExe) == 0;
2502
2503 // open32 does not support DEBUG_ONLY_THIS_PROCESS
2504 if(dwCreationFlags & DEBUG_ONLY_THIS_PROCESS)
2505 dwCreationFlags |= DEBUG_PROCESS;
2506
2507 //Only use WGSS to launch the app if it's not PE or PE & win32k loaded
2508 if(!fPEExe || (fPEExe && fWin32k))
2509 {
2510
2511 trylaunchagain:
2512 if (O32_CreateProcessA(szAppName, lpCommandLine, lpProcessAttributes,
2513 lpThreadAttributes, bInheritHandles, dwCreationFlags,
2514 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
2515 lpProcessInfo) == TRUE)
2516 {
2517 if (dwCreationFlags & DEBUG_PROCESS && pThreadDB != NULL)
2518 {
2519 if(pThreadDB->o.odin.pidDebuggee != 0)
2520 {
2521 // TODO: handle this
2522 dprintf(("KERNEL32: CreateProcess ERROR: This thread is already a debugger\n"));
2523 }
2524 else
2525 {
2526 pThreadDB->o.odin.pidDebuggee = lpProcessInfo->dwProcessId;
2527 OSLibStartDebugger((ULONG*)&pThreadDB->o.odin.pidDebuggee);
2528 }
2529 }
2530 else pThreadDB->o.odin.pidDebuggee = 0;
2531
2532 if(lpProcessInfo)
2533 {
2534 lpProcessInfo->dwThreadId = MAKE_THREADID(lpProcessInfo->dwProcessId, lpProcessInfo->dwThreadId);
2535 }
2536
2537 rc = TRUE;
2538 goto finished;
2539 }
2540 else
2541 if(!oldlibpath)
2542 {//might have failed because it wants to load dlls in its current directory
2543 // Add the application directory to the ENDLIBPATH, so dlls can be found there
2544 // Only necessary for OS/2 applications
2545 oldlibpath = (char *)calloc(4096, 1);
2546 if(oldlibpath)
2547 {
2548 OSLibQueryBeginLibpathA(oldlibpath, 4096);
2549
2550 char *tmp = strrchr(szAppName, '\\');
2551 if(tmp) *tmp = 0;
2552
2553 OSLibSetBeginLibpathA(szAppName);
2554 if(tmp) *tmp = '\\';
2555
2556 goto trylaunchagain;
2557 }
2558
2559 }
2560 // verify why O32_CreateProcess actually failed.
2561 // If GetLastError() == 191 (ERROR_INVALID_EXE_SIGNATURE)
2562 // we can continue to call "PE.EXE".
2563 // Note: Open32 does not translate ERROR_INVALID_EXE_SIGNATURE,
2564 // it is also valid in Win32.
2565 DWORD dwError = GetLastError();
2566 if (ERROR_INVALID_EXE_SIGNATURE != dwError && ERROR_FILE_NOT_FOUND != dwError && ERROR_ACCESS_DENIED != dwError)
2567 {
2568 dprintf(("CreateProcess: O32_CreateProcess failed with rc=%d, not PE-executable !", dwError));
2569
2570 // the current value of GetLastError() is still valid.
2571 rc = FALSE;
2572 goto finished;
2573 }
2574 }
2575
2576 // else ...
2577
2578 //probably a win32 exe, so run it in the pe loader
2579 dprintf(("KERNEL32: CreateProcess %s %s", szAppName, lpCommandLine));
2580
2581 if(fPEExe)
2582 {
2583 LPCSTR lpszExecutable;
2584 int iNewCommandLineLength;
2585
2586 // calculate base length for the new command line
2587 iNewCommandLineLength = strlen(szAppName) + strlen(lpCommandLine);
2588
2589 if(SubSystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
2590 lpszExecutable = szPECmdLoader;
2591 else
2592 lpszExecutable = szPEGUILoader;
2593
2594 // 2002-04-24 PH
2595 // set the ODIN32.DEBUG_CHILD environment variable to start new PE processes
2596 // under a new instance of the (IPMD) debugger.
2597 const char *pszDebugChildArg = "";
2598#ifdef DEBUG
2599 char szDebugChild[512];
2600 const char *pszChildDebugger = getenv("ODIN32.DEBUG_CHILD");
2601 if (pszChildDebugger)
2602 {
2603 /*
2604 * Change the executable to the debugger (icsdebug.exe) and
2605 * move the previous executable onto the commandline.
2606 */
2607 szDebugChild[0] = ' ';
2608 strcpy(&szDebugChild[1], lpszExecutable);
2609 iNewCommandLineLength += strlen(&szDebugChild[0]);
2610
2611 pszDebugChildArg = &szDebugChild[0];
2612 lpszExecutable = pszChildDebugger;
2613 }
2614#endif
2615
2616 //SvL: Allright. Before we call O32_CreateProcess, we must take care of
2617 // lpCurrentDirectory ourselves. (Open32 ignores it!)
2618 if(lpCurrentDirectory) {
2619 char *newcmdline;
2620
2621 newcmdline = (char *)malloc(strlen(lpCurrentDirectory) + iNewCommandLineLength + 64);
2622 sprintf(newcmdline, "%s /OPT:[CURDIR=%s] %s %s", pszDebugChildArg, lpCurrentDirectory, szAppName, lpCommandLine);
2623 free(cmdline);
2624 cmdline = newcmdline;
2625 }
2626 else {
2627 char *newcmdline;
2628
2629 newcmdline = (char *)malloc(iNewCommandLineLength + 16);
2630 sprintf(newcmdline, "%s %s %s", pszDebugChildArg, szAppName, lpCommandLine);
2631 free(cmdline);
2632 cmdline = newcmdline;
2633 }
2634
2635 dprintf(("KERNEL32: CreateProcess starting [%s],[%s]",
2636 lpszExecutable,
2637 cmdline));
2638
2639 rc = O32_CreateProcessA(lpszExecutable, (LPCSTR)cmdline,lpProcessAttributes,
2640 lpThreadAttributes, bInheritHandles, dwCreationFlags,
2641 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
2642 lpProcessInfo);
2643 }
2644 else
2645 if(fNEExe) {//16 bits windows app
2646 char *newcmdline;
2647
2648 newcmdline = (char *)malloc(strlen(szAppName) + strlen(cmdline) + strlen(szPEGUILoader) + strlen(lpCommandLine) + 32);
2649
2650 sprintf(newcmdline, " /PELDR=[%s] %s", szPEGUILoader, szAppName, lpCommandLine);
2651 free(cmdline);
2652 cmdline = newcmdline;
2653 //Force Open32 to use DosStartSession (DosExecPgm won't do)
2654 dwCreationFlags |= CREATE_NEW_PROCESS_GROUP;
2655
2656 dprintf(("KERNEL32: CreateProcess starting [%s],[%s]",
2657 szNELoader,
2658 cmdline));
2659 rc = O32_CreateProcessA(szNELoader, (LPCSTR)cmdline, lpProcessAttributes,
2660 lpThreadAttributes, bInheritHandles, dwCreationFlags,
2661 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
2662 lpProcessInfo);
2663 }
2664 else {//os/2 app??
2665 rc = O32_CreateProcessA(szAppName, (LPCSTR)lpCommandLine, lpProcessAttributes,
2666 lpThreadAttributes, bInheritHandles, dwCreationFlags,
2667 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
2668 lpProcessInfo);
2669 }
2670 if(!lpEnvironment) {
2671 // Restore old ENDLIBPATH variable
2672 // TODO:
2673 }
2674
2675 if(rc == TRUE)
2676 {
2677 if (dwCreationFlags & DEBUG_PROCESS && pThreadDB != NULL)
2678 {
2679 if(pThreadDB->o.odin.pidDebuggee != 0)
2680 {
2681 // TODO: handle this
2682 dprintf(("KERNEL32: CreateProcess ERROR: This thread is already a debugger\n"));
2683 }
2684 else
2685 {
2686 pThreadDB->o.odin.pidDebuggee = lpProcessInfo->dwProcessId;
2687 OSLibStartDebugger((ULONG*)&pThreadDB->o.odin.pidDebuggee);
2688 }
2689 }
2690 else
2691 pThreadDB->o.odin.pidDebuggee = 0;
2692 }
2693 if(lpProcessInfo)
2694 {
2695 lpProcessInfo->dwThreadId = MAKE_THREADID(lpProcessInfo->dwProcessId, lpProcessInfo->dwThreadId);
2696 dprintf(("KERNEL32: CreateProcess returned %d hPro:%x hThr:%x pid:%x tid:%x\n",
2697 rc, lpProcessInfo->hProcess, lpProcessInfo->hThread,
2698 lpProcessInfo->dwProcessId,lpProcessInfo->dwThreadId));
2699 }
2700 else
2701 dprintf(("KERNEL32: CreateProcess returned %d\n", rc));
2702
2703finished:
2704
2705 if(oldlibpath) {
2706 OSLibSetBeginLibpathA(oldlibpath);
2707 free(oldlibpath);
2708 }
2709 if(cmdline) free(cmdline);
2710 if(newenv) free(newenv);
2711 return(rc);
2712}
2713//******************************************************************************
2714//******************************************************************************
2715BOOL WIN32API CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
2716 PSECURITY_ATTRIBUTES lpProcessAttributes,
2717 PSECURITY_ATTRIBUTES lpThreadAttributes,
2718 BOOL bInheritHandles, DWORD dwCreationFlags,
2719 LPVOID lpEnvironment,
2720 LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
2721 LPPROCESS_INFORMATION lpProcessInfo)
2722{
2723 BOOL rc;
2724 char *astring1 = 0, *astring2 = 0, *astring3 = 0;
2725
2726 dprintf(("KERNEL32: CreateProcessW"));
2727 if(lpApplicationName)
2728 astring1 = UnicodeToAsciiString((LPWSTR)lpApplicationName);
2729 if(lpCommandLine)
2730 astring2 = UnicodeToAsciiString(lpCommandLine);
2731 if(lpCurrentDirectory)
2732 astring3 = UnicodeToAsciiString((LPWSTR)lpCurrentDirectory);
2733 if(lpEnvironment) {
2734 // use a special flag instead of converting the environment here
2735 dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
2736 }
2737 rc = CreateProcessA(astring1, astring2, lpProcessAttributes, lpThreadAttributes,
2738 bInheritHandles, dwCreationFlags, lpEnvironment,
2739 astring3, (LPSTARTUPINFOA)lpStartupInfo,
2740 lpProcessInfo);
2741 if(astring3) FreeAsciiString(astring3);
2742 if(astring2) FreeAsciiString(astring2);
2743 if(astring1) FreeAsciiString(astring1);
2744 return(rc);
2745}
2746//******************************************************************************
2747//******************************************************************************
2748HINSTANCE WIN32API WinExec(LPCSTR lpCmdLine, UINT nCmdShow)
2749{
2750 STARTUPINFOA startinfo = {0};
2751 PROCESS_INFORMATION procinfo;
2752 DWORD rc;
2753 HINSTANCE hInstance;
2754
2755 dprintf(("KERNEL32: WinExec lpCmdLine='%s' nCmdShow=%d\n", lpCmdLine));
2756 startinfo.cb = sizeof(startinfo);
2757 startinfo.dwFlags = STARTF_USESHOWWINDOW;
2758 startinfo.wShowWindow = nCmdShow;
2759 if(CreateProcessA(NULL, (LPSTR)lpCmdLine, NULL, NULL, FALSE, 0, NULL, NULL,
2760 &startinfo, &procinfo) == FALSE)
2761 {
2762 hInstance = (HINSTANCE)GetLastError();
2763 if(hInstance >= 32) {
2764 hInstance = 11;
2765 }
2766 dprintf(("KERNEL32: WinExec failed with rc %d", hInstance));
2767 return hInstance;
2768 }
2769 //block until the launched app waits for input (or a timeout of 15 seconds)
2770 //TODO: Shouldn't call Open32, but the api in user32..
2771 if(fVersionWarp3) {
2772 Sleep(1000); //WaitForInputIdle not available in Warp 3
2773 }
2774 else {
2775 dprintf(("Calling WaitForInputIdle %x %d", procinfo.hProcess, 15000));
2776 rc = WaitForInputIdle(procinfo.hProcess, 15000);
2777#ifdef DEBUG
2778 if(rc != 0) {
2779 dprintf(("WinExec: WaitForInputIdle %x returned %x", procinfo.hProcess, rc));
2780 }
2781 else dprintf(("WinExec: WaitForInputIdle successfull"));
2782#endif
2783 }
2784 CloseHandle(procinfo.hThread);
2785 CloseHandle(procinfo.hProcess);
2786 return 33;
2787}
2788//******************************************************************************
2789//******************************************************************************
2790DWORD WIN32API WaitForInputIdle(HANDLE hProcess, DWORD dwTimeOut)
2791{
2792 dprintf(("USER32: WaitForInputIdle %x %d\n", hProcess, dwTimeOut));
2793
2794 if(fVersionWarp3) {
2795 Sleep(1000);
2796 return 0;
2797 }
2798 else return O32_WaitForInputIdle(hProcess, dwTimeOut);
2799}
2800/**********************************************************************
2801 * LoadModule (KERNEL32.499)
2802 *
2803 * Wine: 20000909
2804 *
2805 * Copyright 1995 Alexandre Julliard
2806 */
2807HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock )
2808{
2809 LOADPARAMS *params = (LOADPARAMS *)paramBlock;
2810 PROCESS_INFORMATION info;
2811 STARTUPINFOA startup;
2812 HINSTANCE hInstance;
2813 LPSTR cmdline, p;
2814 char filename[MAX_PATH];
2815 BYTE len;
2816
2817 dprintf(("LoadModule %s %x", name, paramBlock));
2818
2819 if (!name) return ERROR_FILE_NOT_FOUND;
2820
2821 if (!SearchPathA( NULL, name, ".exe", sizeof(filename), filename, NULL ) &&
2822 !SearchPathA( NULL, name, NULL, sizeof(filename), filename, NULL ))
2823 return GetLastError();
2824
2825 len = (BYTE)params->lpCmdLine[0];
2826 if (!(cmdline = (LPSTR)HeapAlloc( GetProcessHeap(), 0, strlen(filename) + len + 2 )))
2827 return ERROR_NOT_ENOUGH_MEMORY;
2828
2829 strcpy( cmdline, filename );
2830 p = cmdline + strlen(cmdline);
2831 *p++ = ' ';
2832 memcpy( p, params->lpCmdLine + 1, len );
2833 p[len] = 0;
2834
2835 memset( &startup, 0, sizeof(startup) );
2836 startup.cb = sizeof(startup);
2837 if (params->lpCmdShow)
2838 {
2839 startup.dwFlags = STARTF_USESHOWWINDOW;
2840 startup.wShowWindow = params->lpCmdShow[1];
2841 }
2842
2843 if (CreateProcessA( filename, cmdline, NULL, NULL, FALSE, 0,
2844 params->lpEnvAddress, NULL, &startup, &info ))
2845 {
2846 /* Give 15 seconds to the app to come up */
2847 if ( WaitForInputIdle ( info.hProcess, 15000 ) == 0xFFFFFFFF )
2848 dprintf(("ERROR: WaitForInputIdle failed: Error %ld\n", GetLastError() ));
2849 hInstance = 33;
2850 /* Close off the handles */
2851 CloseHandle( info.hThread );
2852 CloseHandle( info.hProcess );
2853 }
2854 else if ((hInstance = GetLastError()) >= 32)
2855 {
2856 dprintf(("ERROR: Strange error set by CreateProcess: %d\n", hInstance ));
2857 hInstance = 11;
2858 }
2859
2860 HeapFree( GetProcessHeap(), 0, cmdline );
2861 return hInstance;
2862}
2863//******************************************************************************
2864//******************************************************************************
2865FARPROC WIN32API GetProcAddress(HMODULE hModule, LPCSTR lpszProc)
2866{
2867 Win32ImageBase *winmod;
2868 FARPROC proc = 0;
2869 ULONG ulAPIOrdinal;
2870
2871 if(hModule == 0 || hModule == -1 || (WinExe && hModule == WinExe->getInstanceHandle())) {
2872 winmod = WinExe;
2873 }
2874 else winmod = (Win32ImageBase *)Win32DllBase::findModule((HINSTANCE)hModule);
2875
2876 if(winmod) {
2877 ulAPIOrdinal = (ULONG)lpszProc;
2878 if (ulAPIOrdinal <= 0x0000FFFF) {
2879 proc = (FARPROC)winmod->getApi((int)ulAPIOrdinal);
2880 }
2881 else
2882 if (lpszProc && *lpszProc) {
2883 proc = (FARPROC)winmod->getApi((char *)lpszProc);
2884 }
2885 if(proc == 0) {
2886#ifdef DEBUG
2887 if(ulAPIOrdinal <= 0x0000FFFF) {
2888 dprintf(("GetProcAddress %x %x not found!", hModule, ulAPIOrdinal));
2889 }
2890 else dprintf(("GetProcAddress %x %s not found!", hModule, lpszProc));
2891#endif
2892 SetLastError(ERROR_PROC_NOT_FOUND);
2893 return 0;
2894 }
2895 if(HIWORD(lpszProc))
2896 dprintf(("KERNEL32: GetProcAddress %s from %X returned %X\n", lpszProc, hModule, proc));
2897 else dprintf(("KERNEL32: GetProcAddress %x from %X returned %X\n", lpszProc, hModule, proc));
2898
2899 SetLastError(ERROR_SUCCESS);
2900 return proc;
2901 }
2902 proc = (FARPROC)OSLibDosGetProcAddress(hModule, lpszProc);
2903 if(HIWORD(lpszProc))
2904 dprintf(("KERNEL32: GetProcAddress %s from %X returned %X\n", lpszProc, hModule, proc));
2905 else dprintf(("KERNEL32: GetProcAddress %x from %X returned %X\n", lpszProc, hModule, proc));
2906 SetLastError(ERROR_SUCCESS);
2907 return(proc);
2908}
2909//******************************************************************************
2910// ODIN_SetProcAddress: Override a dll export
2911//
2912// Parameters:
2913// HMODULE hModule Module handle
2914// LPCSTR lpszProc Export name or ordinal
2915// FARPROC pfnNewProc New export function address
2916//
2917// Returns: Success -> old address of export
2918// Failure -> -1
2919//
2920//******************************************************************************
2921FARPROC WIN32API ODIN_SetProcAddress(HMODULE hModule, LPCSTR lpszProc,
2922 FARPROC pfnNewProc)
2923{
2924 Win32ImageBase *winmod;
2925 FARPROC proc;
2926 ULONG ulAPIOrdinal;
2927
2928 if(hModule == 0 || hModule == -1 || (WinExe && hModule == WinExe->getInstanceHandle())) {
2929 winmod = WinExe;
2930 }
2931 else winmod = (Win32ImageBase *)Win32DllBase::findModule((HINSTANCE)hModule);
2932
2933 if(winmod) {
2934 ulAPIOrdinal = (ULONG)lpszProc;
2935 if (ulAPIOrdinal <= 0x0000FFFF) {
2936 proc = (FARPROC)winmod->setApi((int)ulAPIOrdinal, (ULONG)pfnNewProc);
2937 }
2938 else proc = (FARPROC)winmod->setApi((char *)lpszProc, (ULONG)pfnNewProc);
2939 if(proc == 0) {
2940#ifdef DEBUG
2941 if(ulAPIOrdinal <= 0x0000FFFF) {
2942 dprintf(("ODIN_SetProcAddress %x %x not found!", hModule, ulAPIOrdinal));
2943 }
2944 else dprintf(("ODIN_SetProcAddress %x %s not found!", hModule, lpszProc));
2945#endif
2946 SetLastError(ERROR_PROC_NOT_FOUND);
2947 return (FARPROC)-1;
2948 }
2949 if(HIWORD(lpszProc))
2950 dprintf(("KERNEL32: ODIN_SetProcAddress %s from %X returned %X\n", lpszProc, hModule, proc));
2951 else dprintf(("KERNEL32: ODIN_SetProcAddress %x from %X returned %X\n", lpszProc, hModule, proc));
2952
2953 SetLastError(ERROR_SUCCESS);
2954 return proc;
2955 }
2956 SetLastError(ERROR_INVALID_HANDLE);
2957 return (FARPROC)-1;
2958}
2959//******************************************************************************
2960//******************************************************************************
2961UINT WIN32API GetProcModuleFileNameA(ULONG lpvAddress, LPSTR lpszFileName, UINT cchFileNameMax)
2962{
2963 LPSTR lpszModuleName;
2964 Win32ImageBase *image = NULL;
2965 int len;
2966
2967 dprintf(("GetProcModuleFileNameA %x %x %d", lpvAddress, lpszFileName, cchFileNameMax));
2968
2969 if(WinExe && WinExe->insideModule(lpvAddress) && WinExe->insideModuleCode(lpvAddress)) {
2970 image = WinExe;
2971 }
2972 else {
2973 Win32DllBase *dll = Win32DllBase::findModuleByAddr(lpvAddress);
2974 if(dll && dll->insideModuleCode(lpvAddress)) {
2975 image = dll;
2976 }
2977 }
2978 if(image == NULL) {
2979 dprintf(("GetProcModuleFileNameA: address not found!!"));
2980 return 0;
2981 }
2982 len = strlen(image->getFullPath());
2983 if(len < cchFileNameMax) {
2984 strcpy(lpszFileName, image->getFullPath());
2985 return len+1; //??
2986 }
2987 else {
2988 dprintf(("GetProcModuleFileNameA: destination string too small!!"));
2989 return 0;
2990 }
2991}
2992//******************************************************************************
2993//******************************************************************************
2994BOOL WIN32API DisableThreadLibraryCalls(HMODULE hModule)
2995{
2996 Win32DllBase *winmod;
2997 FARPROC proc;
2998 ULONG ulAPIOrdinal;
2999
3000 winmod = Win32DllBase::findModule((HINSTANCE)hModule);
3001 if(winmod)
3002 {
3003 // don't call ATTACH/DETACH thread functions in DLL
3004 winmod->disableThreadLibraryCalls();
3005 return TRUE;
3006 }
3007 else
3008 {
3009 // raise error condition
3010 SetLastError(ERROR_INVALID_HANDLE);
3011 return FALSE;
3012 }
3013}
3014//******************************************************************************
3015// Forwarder for PSAPI.DLL
3016//
3017// Returns the handles of all loaded modules
3018//
3019//******************************************************************************
3020BOOL WINAPI PSAPI_EnumProcessModules(HANDLE hProcess, HMODULE *lphModule,
3021 DWORD cb, LPDWORD lpcbNeeded)
3022{
3023 DWORD count;
3024 DWORD countMax;
3025 HMODULE hModule;
3026
3027 dprintf(("KERNEL32: EnumProcessModules %p, %ld, %p", lphModule, cb, lpcbNeeded));
3028
3029 if ( lphModule == NULL )
3030 cb = 0;
3031
3032 if ( lpcbNeeded != NULL )
3033 *lpcbNeeded = 0;
3034
3035 count = 0;
3036 countMax = cb / sizeof(HMODULE);
3037
3038 count = Win32DllBase::enumDlls(lphModule, countMax);
3039
3040 if ( lpcbNeeded != NULL )
3041 *lpcbNeeded = sizeof(HMODULE) * count;
3042
3043 return TRUE;
3044}
3045//******************************************************************************
3046// Forwarder for PSAPI.DLL
3047//
3048// Returns some information about the module identified by hModule
3049//
3050//******************************************************************************
3051BOOL WINAPI PSAPI_GetModuleInformation(HANDLE hProcess, HMODULE hModule,
3052 LPMODULEINFO lpmodinfo, DWORD cb)
3053{
3054 BOOL ret = FALSE;
3055 Win32DllBase *winmod = NULL;
3056
3057 dprintf(("KERNEL32: GetModuleInformation hModule=%x", hModule));
3058
3059 if (!lpmodinfo || cb < sizeof(MODULEINFO)) return FALSE;
3060
3061 winmod = Win32DllBase::findModule((HINSTANCE)hModule);
3062 if (!winmod) {
3063 dprintf(("GetModuleInformation failed to find module"));
3064 return FALSE;
3065 }
3066
3067 lpmodinfo->SizeOfImage = winmod->getImageSize();
3068 lpmodinfo->EntryPoint = (LPVOID)winmod->getEntryPoint();
3069 lpmodinfo->lpBaseOfDll = (void*)hModule;
3070
3071 return TRUE;
3072}
3073//******************************************************************************
3074//******************************************************************************
3075/**
3076 * Gets the startup info which was passed to CreateProcess when
3077 * this process was created.
3078 *
3079 * @param lpStartupInfo Where to put the startup info.
3080 * Please don't change the strings :)
3081 * @status Partially Implemented.
3082 * @author knut st. osmundsen <bird@anduin.net>
3083 * @remark The three pointers of the structure is just fake.
3084 * @remark Pretty much identical to current wine code.
3085 */
3086void WIN32API GetStartupInfoA(LPSTARTUPINFOA lpStartupInfo)
3087{
3088 dprintf2(("KERNEL32: GetStartupInfoA %x\n", lpStartupInfo));
3089 *lpStartupInfo = StartupInfo;
3090}
3091
3092
3093/**
3094 * Gets the startup info which was passed to CreateProcess when
3095 * this process was created.
3096 *
3097 * @param lpStartupInfo Where to put the startup info.
3098 * Please don't change the strings :)
3099 * @status Partially Implemented.
3100 * @author knut st. osmundsen <bird@anduin.net>
3101 * @remark The three pointers of the structure is just fake.
3102 * @remark Similar to wine code, but they use RtlCreateUnicodeStringFromAsciiz
3103 * for creating the UNICODE strings and are doing so for each call.
3104 * As I don't wanna call NTDLL code from kernel32 I take the easy path.
3105 */
3106void WIN32API GetStartupInfoW(LPSTARTUPINFOW lpStartupInfo)
3107{
3108 /*
3109 * Converted once, this information shouldn't change...
3110 */
3111
3112 dprintf2(("KERNEL32: GetStartupInfoW %x\n", lpStartupInfo));
3113
3114 //assumes the structs are identical but for the strings pointed to.
3115 memcpy(lpStartupInfo, &StartupInfo, sizeof(STARTUPINFOA));
3116 lpStartupInfo->cb = sizeof(STARTUPINFOW); /* this really should be the same size else we're in for trouble.. :) */
3117
3118 /*
3119 * First time conversion only as this should be pretty static.
3120 * See remark!
3121 */
3122 static LPWSTR pwcReserved = NULL;
3123 static LPWSTR pwcDesktop = NULL;
3124 static LPWSTR pwcTitle = NULL;
3125
3126 if (lpStartupInfo->lpReserved && pwcReserved)
3127 pwcReserved = AsciiToUnicodeString((LPCSTR)lpStartupInfo->lpReserved);
3128 lpStartupInfo->lpReserved = pwcReserved;
3129
3130 if (lpStartupInfo->lpDesktop && pwcDesktop)
3131 pwcDesktop = AsciiToUnicodeString((LPCSTR)lpStartupInfo->lpDesktop);
3132 lpStartupInfo->lpDesktop = pwcDesktop;
3133
3134 if (lpStartupInfo->lpTitle && pwcTitle)
3135 pwcTitle = AsciiToUnicodeString((LPCSTR)lpStartupInfo->lpTitle);
3136 lpStartupInfo->lpTitle = pwcTitle;
3137}
3138
3139} // extern "C"
3140
Note: See TracBrowser for help on using the repository browser.