source: trunk/src/kernel32/wprocess.cpp@ 8327

Last change on this file since 8327 was 8327, checked in by sandervl, 23 years ago

PH: memory leak fixes; extra checks for NULL pointers; CreateProcess changes for debug option; GetModuleFileName doesn't count 0 terminator

File size: 83.2 KB
Line 
1/* $Id: wprocess.cpp,v 1.150 2002-04-29 17:05:30 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 *
9 * NOTE: Even though Odin32 OS/2 apps don't switch FS selectors,
10 * we still allocate a TEB to store misc information.
11 *
12 * TODO: What happens when a dll is first loaded as LOAD_LIBRARY_AS_DATAFILE
13 * and then for real? (first one not freed of course)
14 *
15 * Project Odin Software License can be found in LICENSE.TXT
16 *
17 */
18#include <odin.h>
19#include <odinwrap.h>
20#include <os2win.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include <unicode.h>
26#include "windllbase.h"
27#include "winexebase.h"
28#include "windllpeldr.h"
29#include "winexepeldr.h"
30#include "windlllx.h"
31#include <vmutex.h>
32#include <handlemanager.h>
33
34#include "odin32validate.h"
35#include "exceptutil.h"
36#include "oslibdos.h"
37#include "oslibmisc.h"
38#include "oslibdebug.h"
39#include "hmcomm.h"
40
41#include "console.h"
42#include "cio.h"
43#include "versionos2.h" /*PLF Wed 98-03-18 02:36:51*/
44#include <wprocess.h>
45#include "mmap.h"
46#include "initterm.h"
47
48#define DBG_LOCALLOG DBG_wprocess
49#include "dbglocal.h"
50
51#ifdef PROFILE
52#include <perfview.h>
53#include <profiler.h>
54#endif /* PROFILE */
55
56
57ODINDEBUGCHANNEL(KERNEL32-WPROCESS)
58
59
60/*******************************************************************************
61* Global Variables *
62*******************************************************************************/
63BOOL fIsOS2Image = FALSE; /* TRUE -> Odin32 OS/2 application (not converted!) */
64 /* FALSE -> otherwise */
65BOOL fExitProcess = FALSE;
66
67//Commandlines
68PCSTR pszCmdLineA; /* ASCII/ANSII commandline. */
69PCWSTR pszCmdLineW; /* Unicode commandline. */
70
71//Process database
72PDB ProcessPDB = {0};
73STARTUPINFOA StartupInfo = {0};
74CHAR unknownPDBData[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 ,0 ,0};
75USHORT ProcessTIBSel = 0;
76DWORD *TIBFlatPtr = 0;
77
78//list of thread database structures
79static TEB *threadList = 0;
80static VMutex threadListMutex;
81
82//TODO: This should not be here: (need to rearrange NTDLL; kernel32 can't depend on ntdll)
83BOOLEAN (* WINAPI RtlAllocateAndInitializeSid) ( PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
84 BYTE nSubAuthorityCount,
85 DWORD nSubAuthority0,
86 DWORD nSubAuthority1,
87 DWORD nSubAuthority2,
88 DWORD nSubAuthority3,
89 DWORD nSubAuthority4,
90 DWORD nSubAuthority5,
91 DWORD nSubAuthority6,
92 DWORD nSubAuthority7,
93 PSID *pSid);
94static HINSTANCE hInstNTDll = 0;
95
96//******************************************************************************
97//******************************************************************************
98TEB *WIN32API GetThreadTEB()
99{
100 if(TIBFlatPtr == NULL) {
101 return 0;
102 }
103 return (TEB *)*TIBFlatPtr;
104}
105//******************************************************************************
106//******************************************************************************
107TEB *WIN32API GetTEBFromThreadId(ULONG threadId)
108{
109 TEB *teb = threadList;
110
111 threadListMutex.enter();
112 while(teb) {
113 if(teb->o.odin.threadId == threadId) {
114 break;
115 }
116 teb = teb->o.odin.next;
117 }
118 threadListMutex.leave();
119 return teb;
120}
121//******************************************************************************
122//******************************************************************************
123TEB *WIN32API GetTEBFromThreadHandle(HANDLE hThread)
124{
125 TEB *teb = threadList;
126
127 threadListMutex.enter();
128 while(teb) {
129 if(teb->o.odin.hThread == hThread) {
130 break;
131 }
132 teb = teb->o.odin.next;
133 }
134 threadListMutex.leave();
135 return teb;
136}
137//******************************************************************************
138// Set up the TIB selector and memory for the current thread
139//******************************************************************************
140TEB * WIN32API InitializeTIB(BOOL fMainThread)
141{
142 TEB *winteb;
143 ULONG hThreadMain;
144 USHORT tibsel;
145
146 //Allocate one dword to store the flat address of our TEB
147 if(fMainThread) {
148 dprintf(("InitializeTIB Process handle %x, id %x", GetCurrentProcess(), GetCurrentProcessId()));
149
150 TIBFlatPtr = (DWORD *)OSLibAllocThreadLocalMemory(1);
151 if(TIBFlatPtr == 0) {
152 dprintf(("InitializeTIB: local thread memory alloc failed!!"));
153 DebugInt3();
154 return NULL;
155 }
156 //SvL: This doesn't really create a thread, but only sets up the
157 // handle of thread 0
158 hThreadMain = HMCreateThread(NULL, 0, 0, 0, 0, 0, TRUE);
159 }
160 if(OSLibAllocSel(sizeof(TEB), &tibsel) == FALSE)
161 {
162 dprintf(("InitializeTIB: selector alloc failed!!"));
163 DebugInt3();
164 return NULL;
165 }
166 winteb = (TEB *)OSLibSelToFlat(tibsel);
167 if(winteb == NULL)
168 {
169 dprintf(("InitializeTIB: DosSelToFlat failed!!"));
170 DebugInt3();
171 return NULL;
172 }
173 memset(winteb, 0, sizeof(TEB));
174 *TIBFlatPtr = (DWORD)winteb;
175
176 winteb->except = (PVOID)-1; /* 00 Head of exception handling chain */
177 winteb->stack_top = (PVOID)OSLibGetTIB(TIB_STACKTOP); /* 04 Top of thread stack */
178 winteb->stack_low = (PVOID)OSLibGetTIB(TIB_STACKLOW); /* 08 Stack low-water mark */
179 winteb->htask16 = (USHORT)OSLibGetPIB(PIB_TASKHNDL); /* 0c Win16 task handle */
180 winteb->stack_sel = getSS(); /* 0e 16-bit stack selector */
181 winteb->self = winteb; /* 18 Pointer to this structure */
182 winteb->flags = TEBF_WIN32; /* 1c Flags */
183 winteb->queue = 0; /* 28 Message queue */
184 winteb->tls_ptr = &winteb->tls_array[0]; /* 2c Pointer to TLS array */
185 winteb->process = &ProcessPDB; /* 30 owning process (used by NT3.51 applets)*/
186
187 winteb->delta_priority = THREAD_PRIORITY_NORMAL;
188 winteb->process = &ProcessPDB;
189//// winteb->exit_code = 0x103; /* STILL_ACTIVE */
190 winteb->teb_sel = tibsel;
191 winteb->o.odin.OrgTIBSel = GetFS();
192 winteb->o.odin.pWsockData = NULL;
193 winteb->o.odin.threadId = 0xFFFFFFFF;
194 winteb->o.odin.threadId = GetCurrentThreadId();
195#ifdef DEBUG
196 winteb->o.odin.dbgCallDepth = 0;
197#endif
198 winteb->o.odin.pMessageBuffer = NULL;
199
200 if(fMainThread) {
201 winteb->o.odin.hThread = hThreadMain;
202// ProcessPDB.startup_info = &StartupInfo;
203 ProcessPDB.unknown10 = (PVOID)&unknownPDBData[0];
204 StartupInfo.cb = sizeof(StartupInfo);
205 StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
206 StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
207 StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
208 }
209 else winteb->o.odin.hThread = GetCurrentThread();
210 winteb->o.odin.lcid = GetUserDefaultLCID();
211
212 threadListMutex.enter();
213 TEB *teblast = threadList;
214 if(!teblast) {
215 threadList = winteb;
216 }
217 else {
218 while(teblast->o.odin.next) {
219 teblast = teblast->o.odin.next;
220 }
221 teblast->o.odin.next = winteb;
222 }
223 winteb->o.odin.next = NULL;
224 threadListMutex.leave();
225
226 if(OSLibGetPIB(PIB_TASKTYPE) == TASKTYPE_PM)
227 {
228 winteb->flags = 0; //todo gui
229 }
230 else winteb->flags = 0; //todo textmode
231
232 //Initialize thread security objects (TODO: Not complete)
233 if(hInstNTDll == 0) {
234 hInstNTDll = LoadLibraryA("NTDLL.DLL");
235 *(ULONG *)&RtlAllocateAndInitializeSid = (ULONG)GetProcAddress(hInstNTDll, "RtlAllocateAndInitializeSid");
236 if(RtlAllocateAndInitializeSid == NULL) {
237 DebugInt3();
238 }
239 }
240 SID_IDENTIFIER_AUTHORITY sidIdAuth = {0};
241 winteb->o.odin.threadinfo.dwType = SECTYPE_PROCESS | SECTYPE_INITIALIZED;
242
243 if (NULL != RtlAllocateAndInitializeSid) {
244 RtlAllocateAndInitializeSid(&sidIdAuth, 1, 0, 0, 0, 0, 0, 0, 0, 0, &winteb->o.odin.threadinfo.SidUser.User.Sid);
245 }
246 else DebugInt3();
247
248 winteb->o.odin.threadinfo.SidUser.User.Attributes = 0; //?????????
249
250 winteb->o.odin.threadinfo.pTokenGroups = (TOKEN_GROUPS*)malloc(sizeof(TOKEN_GROUPS));
251 winteb->o.odin.threadinfo.pTokenGroups->GroupCount = 1;
252
253 if (NULL != RtlAllocateAndInitializeSid) {
254 RtlAllocateAndInitializeSid(&sidIdAuth, 1, 0, 0, 0, 0, 0, 0, 0, 0, &winteb->o.odin.threadinfo.PrimaryGroup.PrimaryGroup);
255 }
256 else DebugInt3();
257
258 winteb->o.odin.threadinfo.pTokenGroups->Groups[0].Sid = winteb->o.odin.threadinfo.PrimaryGroup.PrimaryGroup;
259 winteb->o.odin.threadinfo.pTokenGroups->Groups[0].Attributes = 0; //????
260// pPrivilegeSet = NULL;
261// pTokenPrivileges= NULL;
262// TokenOwner = {0};
263// DefaultDACL = {0};
264// TokenSource = {0};
265 winteb->o.odin.threadinfo.TokenType = TokenPrimary;
266
267 if(fMainThread)
268 {
269 //todo initialize PDB during process creation
270 //todo: initialize TLS array if required
271 //TLS in executable always TLS index 0?
272 ProcessTIBSel = tibsel;
273//// ProcessPDB.exit_code = 0x103; /* STILL_ACTIVE */
274 ProcessPDB.threads = 1;
275 ProcessPDB.running_threads = 1;
276 ProcessPDB.ring0_threads = 1;
277 ProcessPDB.system_heap = GetProcessHeap();
278 ProcessPDB.parent = 0;
279 ProcessPDB.group = &ProcessPDB;
280 ProcessPDB.priority = 8; /* Normal */
281 ProcessPDB.heap = ProcessPDB.system_heap; /* will be changed later on */
282 ProcessPDB.next = NULL;
283 ProcessPDB.winver = 0xffff; /* to be determined */
284 ProcessPDB.server_pid = (void *)GetCurrentProcessId();
285 ProcessPDB.tls_bits[0] = 0; //all tls slots are free
286 ProcessPDB.tls_bits[1] = 0;
287
288 GetSystemTime(&ProcessPDB.creationTime) ;
289
290 /* Initialize the critical section */
291 InitializeCriticalSection( &ProcessPDB.crit_section );
292 }
293 dprintf(("InitializeTIB setup TEB with selector %x", tibsel));
294 dprintf(("InitializeTIB: FS(%x):[0] = %x", GetFS(), QueryExceptionChain()));
295 return winteb;
296}
297//******************************************************************************
298//******************************************************************************
299ULONG WIN32API GetProcessTIBSel()
300{
301 if(fExitProcess) {
302 return 0;
303 }
304 return ProcessTIBSel;
305}
306//******************************************************************************
307// Destroy the TIB selector and memory for the current thread
308//******************************************************************************
309void WIN32API DestroyTIB()
310{
311 SHORT orgtibsel;
312 TEB *winteb;
313
314 dprintf(("DestroyTIB: FS = %x", GetFS()));
315 dprintf(("DestroyTIB: FS:[0] = %x", QueryExceptionChain()));
316
317 winteb = (TEB *)*TIBFlatPtr;
318 if(winteb) {
319 orgtibsel = winteb->o.odin.OrgTIBSel;
320
321 dprintf(("DestroyTIB: OSLibFreeSel %x", winteb->teb_sel));
322
323 threadListMutex.enter();
324 TEB *curteb = threadList;
325 if(curteb == winteb) {
326 threadList = winteb->o.odin.next;
327 }
328 else {
329 while(curteb->o.odin.next != winteb) {
330 curteb = curteb->o.odin.next;
331 if(curteb == NULL) {
332 dprintf(("DestroyTIB: couldn't find teb %x", winteb));
333 DebugInt3();
334 break;
335 }
336 }
337 if(curteb) {
338 curteb->o.odin.next = winteb->o.odin.next;
339 }
340 }
341 threadListMutex.leave();
342
343 // PH 2002-04-11
344 // free allocated memory
345 free( winteb->o.odin.threadinfo.pTokenGroups );
346
347#ifdef DEBUG
348 if (winteb->o.odin.arrstrCallStack != NULL)
349 free( winteb->o.odin.arrstrCallStack );
350#endif
351
352 //Restore our original FS selector
353 SetFS(orgtibsel);
354
355 //And free our own
356 OSLibFreeSel(winteb->teb_sel);
357
358 *TIBFlatPtr = 0;
359 }
360 else dprintf(("Already destroyed TIB"));
361
362 dprintf(("DestroyTIB: FS(%x):[0] = %x", GetFS(), QueryExceptionChain()));
363 return;
364}
365/******************************************************************************/
366/******************************************************************************/
367void SetPDBInstance(HINSTANCE hInstance)
368{
369 ProcessPDB.hInstance = hInstance;
370}
371/******************************************************************************/
372/******************************************************************************/
373void WIN32API RestoreOS2TIB()
374{
375 SHORT orgtibsel;
376 TEB *winteb;
377
378 //If we're running an Odin32 OS/2 application (not converted!), then we
379 //we don't switch FS selectors
380 if(fIsOS2Image) {
381 return;
382 }
383
384 winteb = (TEB *)*TIBFlatPtr;
385 if(winteb) {
386 orgtibsel = winteb->o.odin.OrgTIBSel;
387
388 //Restore our original FS selector
389 SetFS(orgtibsel);
390 }
391}
392/******************************************************************************/
393//Switch to WIN32 TIB (FS selector)
394//NOTE: This is not done for Odin32 applications (LX), unless
395// fForceSwitch is TRUE)
396/******************************************************************************/
397USHORT WIN32API SetWin32TIB(BOOL fForceSwitch)
398{
399 SHORT win32tibsel;
400 TEB *winteb;
401
402 //If we're running an Odin32 OS/2 application (not converted!), then we
403 //we don't switch FS selectors
404 if(fIsOS2Image && !fForceSwitch) {
405 return GetFS();
406 }
407
408 winteb = (TEB *)*TIBFlatPtr;
409 if(winteb) {
410 win32tibsel = winteb->teb_sel;
411
412 //Restore our win32 FS selector
413 return SetReturnFS(win32tibsel);
414 }
415 else {
416 //we didn't create this thread, so allocate a selector now
417 //NOTE: Possible memory leak (i.e. DART threads in WINMM)
418 winteb = InitializeTIB();
419 if(winteb == NULL) {
420 DebugInt3();
421 return GetFS();
422 }
423 win32tibsel = winteb->teb_sel;
424
425 //Restore our win32 FS selector
426 return SetReturnFS(win32tibsel);
427 }
428 // nested calls are OK, OS2ToWinCallback for instance
429 //else DebugInt3();
430
431 return GetFS();
432}
433//******************************************************************************
434//******************************************************************************
435VOID WIN32API ExitProcess(DWORD exitcode)
436{
437 dprintf(("KERNEL32: ExitProcess %d\n", exitcode));
438 dprintf(("KERNEL32: ExitProcess FS = %x\n", GetFS()));
439
440 fExitProcess = TRUE;
441
442 SetOS2ExceptionChain(-1);
443
444 HMDeviceCommClass::CloseOverlappedIOHandlers();
445
446 if(WinExe) {
447 delete(WinExe);
448 WinExe = NULL;
449 }
450
451 //Note: Needs to be done after deleting WinExe (destruction of exe + dll objects)
452 //Flush and delete all open memory mapped files
453 Win32MemMap::deleteAll();
454
455 //SvL: We must make sure no threads are still suspended (with SuspendThread)
456 // OS/2 seems to be unable to terminate the process otherwise (exitlist hang)
457 TEB *teb = threadList;
458 threadListMutex.enter();
459 while(teb) {
460 ResumeThread(teb->o.odin.hThread);
461 teb = teb->o.odin.next;
462 }
463 threadListMutex.leave();
464
465
466#ifdef PROFILE
467 // Note: after this point we do not expect any more Win32-API calls,
468 // so this is probably the best time to dump the gathered profiling
469 // information
470 PerfView_Write();
471 ProfilerWrite();
472 ProfilerTerminate();
473#endif /* PROFILE */
474
475
476
477 //Restore original OS/2 TIB selector
478 DestroyTIB();
479 SetExceptionChain((ULONG)-1);
480
481 //avoid crashes since win32 & OS/2 exception handler aren't identical
482 //(terminate process generates two exceptions)
483 /* @@@PH 1998/02/12 Added Console Support */
484 if (iConsoleIsActive())
485 iConsoleWaitClose();
486
487 O32_ExitProcess(exitcode);
488}
489//******************************************************************************
490//******************************************************************************
491BOOL WIN32API FreeLibrary(HINSTANCE hinstance)
492{
493 Win32DllBase *winmod;
494 BOOL rc;
495
496 SetLastError(ERROR_SUCCESS);
497 //SvL: Ignore FreeLibary for executable
498 if(WinExe && hinstance == WinExe->getInstanceHandle()) {
499 return TRUE;
500 }
501
502 winmod = Win32DllBase::findModule(hinstance);
503 if(winmod) {
504 dprintf(("FreeLibrary %s", winmod->getName()));
505 //Only free it when the nrDynamicLibRef != 0
506 //This prevent problems after ExitProcess:
507 //i.e. dll A is referenced by our exe and loaded with LoadLibrary by dll B
508 // During ExitProcess it's unloaded once (before dll B), dll B calls
509 // FreeLibrary, but our exe also has a reference -> unloaded too many times
510 if(winmod->isDynamicLib()) {
511 winmod->decDynamicLib();
512 winmod->Release();
513 }
514 else {
515 dprintf(("Skipping dynamic unload as nrDynamicLibRef == 0"));
516 }
517 return(TRUE);
518 }
519 dprintf(("WARNING: KERNEL32: FreeLibrary %s %x NOT FOUND!", OSLibGetDllName(hinstance), hinstance));
520 return(TRUE);
521}
522/*****************************************************************************
523 * Name : VOID WIN32API FreeLibraryAndExitThread
524 * Purpose : The FreeLibraryAndExitThread function decrements the reference
525 * count of a loaded dynamic-link library (DLL) by one, and then
526 * calls ExitThread to terminate the calling thread.
527 * The function does not return.
528 *
529 * The FreeLibraryAndExitThread function gives threads that are
530 * created and executed within a dynamic-link library an opportunity
531 * to safely unload the DLL and terminate themselves.
532 * Parameters:
533 * Variables :
534 * Result :
535 * Remark :
536 *****************************************************************************/
537VOID WIN32API FreeLibraryAndExitThread( HMODULE hLibModule, DWORD dwExitCode)
538{
539
540 dprintf(("KERNEL32: FreeLibraryAndExitThread(%08x,%08x)", hLibModule, dwExitCode));
541 FreeLibrary(hLibModule);
542 ExitThread(dwExitCode);
543}
544/******************************************************************************/
545/******************************************************************************/
546/**
547 * LoadLibraryA can be used to map a DLL module into the calling process's
548 * addressspace. It returns a handle that can be used with GetProcAddress to
549 * get addresses of exported entry points (functions and variables).
550 *
551 * LoadLibraryA can also be used to map executable (.exe) modules into the
552 * address to access resources in the module. However, LoadLibrary can't be
553 * used to run an executable (.exe) module.
554 *
555 * @returns Handle to the library which was loaded.
556 * @param lpszLibFile Pointer to zero ASCII string giving the name of the
557 * executable image (either a Dll or an Exe) which is to be
558 * loaded.
559 *
560 * If no extention is specified the default .DLL extention is
561 * appended to the name. End the filename with an '.' if the
562 * file does not have an extention (and don't want the .DLL
563 * appended).
564 *
565 * If no path is specified, this API will use the Odin32
566 * standard search strategy to find the file. This strategy
567 * is described in the method Win32ImageBase::findDLL.
568 *
569 * This API likes to have backslashes (\), but will probably
570 * accept forward slashes too. Win32 SDK docs says that it
571 * should not contain forward slashes.
572 *
573 * Win32 SDK docs adds:
574 * "The name specified is the file name of the module and
575 * is not related to the name stored in the library module
576 * itself, as specified by the LIBRARY keyword in the
577 * module-definition (.def) file."
578 *
579 * @sketch Call LoadLibraryExA with flags set to 0.
580 * @status Odin32 Completely Implemented.
581 * @author Sander van Leeuwen (sandervl@xs4all.nl)
582 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
583 * @remark Forwards to LoadLibraryExA.
584 */
585HINSTANCE WIN32API LoadLibraryA(LPCTSTR lpszLibFile)
586{
587 HINSTANCE hDll;
588
589 dprintf(("KERNEL32: LoadLibraryA(%s) --> LoadLibraryExA(lpszLibFile, 0, 0)",
590 lpszLibFile));
591 hDll = LoadLibraryExA(lpszLibFile, 0, 0);
592 dprintf(("KERNEL32: LoadLibraryA(%s) returns 0x%x",
593 lpszLibFile, hDll));
594 return hDll;
595}
596
597
598/**
599 * LoadLibraryW can be used to map a DLL module into the calling process's
600 * addressspace. It returns a handle that can be used with GetProcAddress to
601 * get addresses of exported entry points (functions and variables).
602 *
603 * LoadLibraryW can also be used to map executable (.exe) modules into the
604 * address to access resources in the module. However, LoadLibrary can't be
605 * used to run an executable (.exe) module.
606 *
607 * @returns Handle to the library which was loaded.
608 * @param lpszLibFile Pointer to Unicode string giving the name of
609 * the executable image (either a Dll or an Exe) which is to
610 * be loaded.
611 *
612 * If no extention is specified the default .DLL extention is
613 * appended to the name. End the filename with an '.' if the
614 * file does not have an extention (and don't want the .DLL
615 * appended).
616 *
617 * If no path is specified, this API will use the Odin32
618 * standard search strategy to find the file. This strategy
619 * is described in the method Win32ImageBase::findDLL.
620 *
621 * This API likes to have backslashes (\), but will probably
622 * accept forward slashes too. Win32 SDK docs says that it
623 * should not contain forward slashes.
624 *
625 * Win32 SDK docs adds:
626 * "The name specified is the file name of the module and
627 * is not related to the name stored in the library module
628 * itself, as specified by the LIBRARY keyword in the
629 * module-definition (.def) file."
630 *
631 * @sketch Convert Unicode name to ascii.
632 * Call LoadLibraryExA with flags set to 0.
633 * free ascii string.
634 * @status Odin32 Completely Implemented.
635 * @author Sander van Leeuwen (sandervl@xs4all.nl)
636 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
637 * @remark Forwards to LoadLibraryExA.
638 */
639HINSTANCE WIN32API LoadLibraryW(LPCWSTR lpszLibFile)
640{
641 char * pszAsciiLibFile;
642 HINSTANCE hDll;
643
644 pszAsciiLibFile = UnicodeToAsciiString(lpszLibFile);
645 dprintf(("KERNEL32: LoadLibraryW(%s) --> LoadLibraryExA(lpszLibFile, 0, 0)",
646 pszAsciiLibFile));
647 hDll = LoadLibraryExA(pszAsciiLibFile, NULL, 0);
648 dprintf(("KERNEL32: LoadLibraryW(%s) returns 0x%x",
649 pszAsciiLibFile, hDll));
650 FreeAsciiString(pszAsciiLibFile);
651
652 return hDll;
653}
654
655
656/**
657 * LoadLibraryExA can be used to map a DLL module into the calling process's
658 * addressspace. It returns a handle that can be used with GetProcAddress to
659 * get addresses of exported entry points (functions and variables).
660 *
661 * LoadLibraryExA can also be used to map executable (.exe) modules into the
662 * address to access resources in the module. However, LoadLibrary can't be
663 * used to run an executable (.exe) module.
664 *
665 * @returns Handle to the library which was loaded.
666 * @param lpszLibFile Pointer to Unicode string giving the name of
667 * the executable image (either a Dll or an Exe) which is to
668 * be loaded.
669 *
670 * If no extention is specified the default .DLL extention is
671 * appended to the name. End the filename with an '.' if the
672 * file does not have an extention (and don't want the .DLL
673 * appended).
674 *
675 * If no path is specified, this API will use the Odin32
676 * standard search strategy to find the file. This strategy
677 * is described in the method Win32ImageBase::findDLL.
678 * This may be alterned by the LOAD_WITH_ALTERED_SEARCH_PATH
679 * flag, see below.
680 *
681 * This API likes to have backslashes (\), but will probably
682 * accept forward slashes too. Win32 SDK docs says that it
683 * should not contain forward slashes.
684 *
685 * Win32 SDK docs adds:
686 * "The name specified is the file name of the module and
687 * is not related to the name stored in the library module
688 * itself, as specified by the LIBRARY keyword in the
689 * module-definition (.def) file."
690 *
691 * @param hFile Reserved. Must be 0.
692 *
693 * @param dwFlags Flags which specifies the taken when loading the module.
694 * The value 0 makes it identical to LoadLibraryA/W.
695 *
696 * Flags:
697 *
698 * DONT_RESOLVE_DLL_REFERENCES
699 * (WinNT/2K feature): Don't load imported modules and
700 * hence don't resolve imported symbols.
701 * DllMain isn't called either. (Which is obvious since
702 * it may use one of the importe symbols.)
703 *
704 * On the other hand, if this flag is NOT set, the system
705 * load imported modules, resolves imported symbols, calls
706 * DllMain for process and thread init and term (if wished
707 * by the module).
708 *
709 *
710 * LOAD_LIBRARY_AS_DATAFILE
711 * If this flag is set, the module is mapped into the
712 * address space but is not prepared for execution. Though
713 * it's preparted for resource API. Hence, you'll use this
714 * flag when you want to load a DLL for extracting
715 * messages or resources from it.
716 *
717 * The resulting handle can be used with any Odin32 API
718 * which operates on resources.
719 * (WinNt/2k supports all resource APIs while Win9x don't
720 * support the specialized resource APIs: LoadBitmap,
721 * LoadCursor, LoadIcon, LoadImage, LoadMenu.)
722 *
723 *
724 * LOAD_WITH_ALTERED_SEARCH_PATH
725 * If this flag is set and lpszLibFile specifies a path
726 * we'll use an alternative file search strategy to find
727 * imported modules. This stratgy is simply to use the
728 * path of the module being loaded instead of the path
729 * of the executable module as the first location
730 * to search for imported modules.
731 *
732 * If this flag is clear, the standard Odin32 standard
733 * search strategy. See Win32ImageBase::findDll for
734 * further information.
735 *
736 * not implemented yet.
737 *
738 * @status Open32 Partially Implemented.
739 * @author Sander van Leeuwen (sandervl@xs4all.nl)
740 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
741 * @remark Forwards to LoadLibraryExA.
742 */
743HINSTANCE WIN32API LoadLibraryExA(LPCTSTR lpszLibFile, HANDLE hFile, DWORD dwFlags)
744{
745 HINSTANCE hDll;
746 Win32DllBase * pModule;
747 char szModname[CCHMAXPATH];
748 BOOL fPath; /* Flags which is set if the */
749 /* lpszLibFile contains a path. */
750 ULONG fPE; /* isPEImage return value. */
751 DWORD Characteristics; //file header's Characteristics
752 char *dot;
753
754 /** @sketch
755 * Some parameter validations is probably useful.
756 */
757 if (!VALID_PSZ(lpszLibFile))
758 {
759 dprintf(("KERNEL32: LoadLibraryExA(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
760 lpszLibFile, hFile, dwFlags, lpszLibFile));
761 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
762 return NULL;
763 }
764 if (!VALID_PSZMAXSIZE(lpszLibFile, CCHMAXPATH))
765 {
766 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): lpszLibFile string too long, %d\n",
767 lpszLibFile, hFile, dwFlags, strlen(lpszLibFile)));
768 SetLastError(ERROR_INVALID_PARAMETER);
769 return NULL;
770 }
771 if ((dwFlags & ~(DONT_RESOLVE_DLL_REFERENCES | LOAD_WITH_ALTERED_SEARCH_PATH | LOAD_LIBRARY_AS_DATAFILE)) != 0)
772 {
773 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): dwFlags have invalid or unsupported flags\n",
774 lpszLibFile, hFile, dwFlags));
775 SetLastError(ERROR_INVALID_PARAMETER);
776 return NULL;
777 }
778
779
780 /** @sketch
781 * First we'll see if the module is allready loaded - either as the EXE or as DLL.
782 * IF Executable present AND libfile matches the modname of the executable THEN
783 * RETURN instance handle of executable.
784 * Endif
785 * IF allready loaded THEN
786 * IF it's a LX dll which isn't loaded and we're using the PeLoader THEN
787 * Set Load library.
788 * Endif
789 * Inc dynamic reference count.
790 * Inc reference count.
791 * RETURN instance handle.
792 * Endif
793 */
794 strcpy(szModname, lpszLibFile);
795 strupr(szModname);
796 dot = strchr(szModname, '.');
797 if(dot == NULL) {
798 //if there's no extension or trainling dot, we
799 //assume it's a dll (see Win32 SDK docs)
800 strcat(szModname, DLL_EXTENSION);
801 }
802 else {
803 if(dot[1] == 0) {
804 //a trailing dot means the module has no extension (SDK docs)
805 *dot = 0;
806 }
807 }
808 if (WinExe != NULL && WinExe->matchModName(szModname))
809 return WinExe->getInstanceHandle();
810
811 pModule = Win32DllBase::findModule((LPSTR)szModname);
812 if (pModule)
813 {
814 pModule->incDynamicLib();
815 pModule->AddRef();
816 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Dll found %s",
817 szModname, hFile, dwFlags, pModule->getInstanceHandle(), pModule->getFullPath()));
818 return pModule->getInstanceHandle();
819 }
820
821
822 /** @sketch
823 * Test if lpszLibFile has a path or not.
824 * Copy the lpszLibFile to szModname, rename the dll and uppercase the name.
825 * IF it hasn't a path THEN
826 * Issue a findDll to find the dll/executable to be loaded.
827 * IF the Dll isn't found THEN
828 * Set last error and RETURN.
829 * Endif.
830 * Endif
831 */
832 fPath = strchr(szModname, '\\') || strchr(szModname, '/');
833 Win32DllBase::renameDll(szModname);
834
835 if (!fPath)
836 {
837 char szModName2[CCHMAXPATH];
838 strcpy(szModName2, szModname);
839 if (!Win32ImageBase::findDll(szModName2, szModname, sizeof(szModname)))
840 {
841 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): module wasn't found. returns NULL",
842 lpszLibFile, hFile, dwFlags));
843 SetLastError(ERROR_FILE_NOT_FOUND);
844 return NULL;
845 }
846 }
847
848 //test if dll is in PE or LX format
849 fPE = Win32ImageBase::isPEImage(szModname, &Characteristics, NULL);
850
851 /** @sketch
852 * IF (!fPeLoader || fPE == failure) THEN
853 * Try load the executable using LoadLibrary
854 * IF successfully loaded THEN
855 * IF LX dll and is using the PE Loader THEN
856 * Set Load library.
857 * Inc reference count.
858 * Endif
859 * Inc dynamic reference count.
860 * RETURN successfully.
861 * Endif
862 * Endif
863 */
864 //only call OS/2 if LX binary or win32k process
865 if (!fPeLoader || fPE != ERROR_SUCCESS)
866 {
867 hDll = OSLibDosLoadModule(szModname);
868 if (hDll)
869 {
870 /* OS/2 dll, system dll, converted dll or win32k took care of it. */
871 pModule = Win32DllBase::findModuleByOS2Handle(hDll);
872 if (pModule)
873 {
874 if (pModule->isLxDll())
875 {
876 ((Win32LxDll *)pModule)->setDllHandleOS2(hDll);
877 if (fPeLoader && pModule->AddRef() == -1)
878 { //-1 -> load failed (attachProcess)
879 delete pModule;
880 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
881 dprintf(("Dll %s refused to be loaded; aborting", szModname));
882 return 0;
883 }
884
885 }
886 pModule->incDynamicLib();
887 }
888 else if (fExeStarted && !fIsOS2Image) {
889 OSLibDosFreeModule(hDll);
890 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
891 dprintf(("Dll %s is not an Odin dll; unload & return failure", szModname));
892 return 0;
893 }
894 else {
895 /* bird 2001-07-10:
896 * let's fail right away instead of hitting DebugInt3s and fail other places.
897 * This is very annoying when running Opera on a debug build with netscape/2
898 * plugins present. We'll make this conditional for the time being.
899 */
900 static BOOL fFailIfUnregisteredLX = -1;
901 if (fFailIfUnregisteredLX == -1)
902 fFailIfUnregisteredLX = getenv("ODIN32.FAIL_IF_UNREGISTEREDLX") != NULL;
903 if (fExeStarted && fFailIfUnregisteredLX)
904 {
905 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Loaded OS/2 dll %s using DosLoadModule. returns NULL.",
906 lpszLibFile, hFile, dwFlags, hDll, szModname));
907 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
908 return NULL;
909 }
910 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Loaded OS/2 dll %s using DosLoadModule.",
911 lpszLibFile, hFile, dwFlags, hDll, szModname));
912 return hDll; //happens when LoadLibrary is called in kernel32's initterm (nor harmful)
913 }
914 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Loaded %s using DosLoadModule.",
915 lpszLibFile, hFile, dwFlags, hDll, szModname));
916 return pModule->getInstanceHandle();
917 }
918 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): DosLoadModule (%s) failed. LastError=%d",
919 lpszLibFile, hFile, dwFlags, szModname, GetLastError()));
920 }
921 else
922 hDll = NULL;
923
924
925 /** @sketch
926 * If PE image THEN
927 * IF LOAD_LIBRARY_AS_DATAFILE or Executable THEN
928 *
929 *
930 * Try load the file using the Win32PeLdrDll class.
931 * <sketch continued further down>
932 * Else
933 * Set last error.
934 * (hDll is NULL)
935 * Endif
936 * return hDll.
937 */
938 if(fPE == ERROR_SUCCESS)
939 {
940 Win32PeLdrDll *peldrDll;
941
942 //SvL: If executable -> load as data file (only resources)
943 if(!(Characteristics & IMAGE_FILE_DLL))
944 {
945 dwFlags |= (LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES);
946 }
947
948 peldrDll = new Win32PeLdrDll(szModname);
949 if (peldrDll == NULL)
950 {
951 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Failed to created instance of Win32PeLdrDll. returns NULL.",
952 lpszLibFile, hFile, dwFlags));
953 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
954 return NULL;
955 }
956
957 /** @sketch
958 * Process dwFlags
959 */
960 if (dwFlags & LOAD_LIBRARY_AS_DATAFILE)
961 {
962 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): LOAD_LIBRARY_AS_DATAFILE",
963 lpszLibFile, hFile, dwFlags));
964 peldrDll->setLoadAsDataFile();
965 peldrDll->disableLibraryCalls();
966 }
967 if (dwFlags & DONT_RESOLVE_DLL_REFERENCES)
968 {
969 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): DONT_RESOLVE_DLL_REFERENCES",
970 lpszLibFile, hFile, dwFlags));
971 peldrDll->disableLibraryCalls();
972 peldrDll->disableImportHandling();
973 }
974 if (dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH)
975 {
976 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Warning dwFlags LOAD_WITH_ALTERED_SEARCH_PATH is not implemented.",
977 lpszLibFile, hFile, dwFlags));
978 //peldrDll->setLoadWithAlteredSearchPath();
979 }
980
981 /** @sketch
982 * Initiate the peldr DLL.
983 * IF successful init THEN
984 * Inc dynamic ref count.
985 * Inc ref count.
986 * Attach to process
987 * IF successful THEN
988 * hDLL <- instance handle.
989 * ELSE
990 * set last error
991 * delete Win32PeLdrDll instance.
992 * Endif
993 * ELSE
994 * set last error
995 * delete Win32PeLdrDll instance.
996 * Endif.
997 */
998 if (peldrDll->init(0))
999 {
1000 peldrDll->AddRef();
1001 if (peldrDll->attachProcess())
1002 {
1003 hDll = peldrDll->getInstanceHandle();
1004 //Must be called *after* attachprocess, since attachprocess may also
1005 //trigger LoadLibrary calls
1006 //Those dlls must not be put in front of this dll in the dynamic
1007 //dll list; or else the unload order is wrong:
1008 //i.e. RPAP3260 loads PNRS3260 in DLL_PROCESS_ATTACH
1009 // this means that in ExitProcess, PNRS3260 needs to be removed
1010 // first since RPAP3260 depends on it
1011 peldrDll->incDynamicLib();
1012 }
1013 else
1014 {
1015 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): attachProcess call to Win32PeLdrDll instance failed. returns NULL.",
1016 lpszLibFile, hFile, dwFlags));
1017 SetLastError(ERROR_DLL_INIT_FAILED);
1018 delete peldrDll;
1019 return NULL;
1020 }
1021 }
1022 else
1023 {
1024 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Failed to init Win32PeLdrDll instance. error=%d returns NULL.",
1025 lpszLibFile, hFile, dwFlags, peldrDll->getError()));
1026 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
1027 delete peldrDll;
1028 return NULL;
1029 }
1030 }
1031 else
1032 {
1033 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x) library wasn't found (%s) or isn't loadable; err %x",
1034 lpszLibFile, hFile, dwFlags, szModname, fPE));
1035 SetLastError(fPE);
1036 return NULL;
1037 }
1038
1039 return hDll;
1040}
1041
1042
1043/**
1044 * LoadLibraryExW can be used to map a DLL module into the calling process's
1045 * addressspace. It returns a handle that can be used with GetProcAddress to
1046 * get addresses of exported entry points (functions and variables).
1047 *
1048 * LoadLibraryExW can also be used to map executable (.exe) modules into the
1049 * address to access resources in the module. However, LoadLibrary can't be
1050 * used to run an executable (.exe) module.
1051 *
1052 * @returns Handle to the library which was loaded.
1053 * @param lpszLibFile Pointer to Unicode string giving the name of
1054 * the executable image (either a Dll or an Exe) which is to
1055 * be loaded.
1056 *
1057 * If no extention is specified the default .DLL extention is
1058 * appended to the name. End the filename with an '.' if the
1059 * file does not have an extention (and don't want the .DLL
1060 * appended).
1061 *
1062 * If no path is specified, this API will use the Odin32
1063 * standard search strategy to find the file. This strategy
1064 * is described in the method Win32ImageBase::findDLL.
1065 * This may be alterned by the LOAD_WITH_ALTERED_SEARCH_PATH
1066 * flag, see below.
1067 *
1068 * This API likes to have backslashes (\), but will probably
1069 * accept forward slashes too. Win32 SDK docs says that it
1070 * should not contain forward slashes.
1071 *
1072 * Win32 SDK docs adds:
1073 * "The name specified is the file name of the module and
1074 * is not related to the name stored in the library module
1075 * itself, as specified by the LIBRARY keyword in the
1076 * module-definition (.def) file."
1077 *
1078 * @param hFile Reserved. Must be 0.
1079 *
1080 * @param dwFlags Flags which specifies the taken when loading the module.
1081 * The value 0 makes it identical to LoadLibraryA/W.
1082 *
1083 * Flags:
1084 *
1085 * DONT_RESOLVE_DLL_REFERENCES
1086 * (WinNT/2K feature): Don't load imported modules and
1087 * hence don't resolve imported symbols.
1088 * DllMain isn't called either. (Which is obvious since
1089 * it may use one of the importe symbols.)
1090 *
1091 * On the other hand, if this flag is NOT set, the system
1092 * load imported modules, resolves imported symbols, calls
1093 * DllMain for process and thread init and term (if wished
1094 * by the module).
1095 *
1096 * LOAD_LIBRARY_AS_DATAFILE
1097 * If this flag is set, the module is mapped into the
1098 * address space but is not prepared for execution. Though
1099 * it's preparted for resource API. Hence, you'll use this
1100 * flag when you want to load a DLL for extracting
1101 * messages or resources from it.
1102 *
1103 * The resulting handle can be used with any Odin32 API
1104 * which operates on resources.
1105 * (WinNt/2k supports all resource APIs while Win9x don't
1106 * support the specialized resource APIs: LoadBitmap,
1107 * LoadCursor, LoadIcon, LoadImage, LoadMenu.)
1108 *
1109 * LOAD_WITH_ALTERED_SEARCH_PATH
1110 * If this flag is set and lpszLibFile specifies a path
1111 * we'll use an alternative file search strategy to find
1112 * imported modules. This stratgy is simply to use the
1113 * path of the module being loaded instead of the path
1114 * of the executable module as the first location
1115 * to search for imported modules.
1116 *
1117 * If this flag is clear, the standard Odin32 standard
1118 * search strategy. See Win32ImageBase::findDll for
1119 * further information.
1120 *
1121 * @sketch Convert Unicode name to ascii.
1122 * Call LoadLibraryExA.
1123 * Free ascii string.
1124 * return handle from LoadLibraryExA.
1125 * @status Open32 Partially Implemented.
1126 * @author Sander van Leeuwen (sandervl@xs4all.nl)
1127 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
1128 * @remark Forwards to LoadLibraryExA.
1129 */
1130HINSTANCE WIN32API LoadLibraryExW(LPCWSTR lpszLibFile, HANDLE hFile, DWORD dwFlags)
1131{
1132 char * pszAsciiLibFile;
1133 HINSTANCE hDll;
1134
1135 pszAsciiLibFile = UnicodeToAsciiString(lpszLibFile);
1136 dprintf(("KERNEL32: LoadLibraryExW(%s, 0x%x, 0x%x) --> LoadLibraryExA",
1137 pszAsciiLibFile, hFile, dwFlags));
1138 hDll = LoadLibraryExA(pszAsciiLibFile, hFile, dwFlags);
1139 dprintf(("KERNEL32: LoadLibraryExW(%s, 0x%x, 0x%x) returns 0x%x",
1140 pszAsciiLibFile, hFile, dwFlags, hDll));
1141 FreeAsciiString(pszAsciiLibFile);
1142
1143 return hDll;
1144}
1145//******************************************************************************
1146//******************************************************************************
1147HINSTANCE16 WIN32API LoadLibrary16(LPCTSTR lpszLibFile)
1148{
1149 dprintf(("ERROR: LoadLibrary16 %s, not implemented", lpszLibFile));
1150 return 0;
1151}
1152//******************************************************************************
1153//******************************************************************************
1154VOID WIN32API FreeLibrary16(HINSTANCE16 hinstance)
1155{
1156 dprintf(("ERROR: FreeLibrary16 %x, not implemented", hinstance));
1157}
1158//******************************************************************************
1159//******************************************************************************
1160FARPROC WIN32API GetProcAddress16(HMODULE hModule, LPCSTR lpszProc)
1161{
1162 dprintf(("ERROR: GetProcAddress16 %x %x, not implemented", hModule, lpszProc));
1163 return 0;
1164}
1165
1166
1167/**
1168 * Internal function which gets the commandline (string) used to start the current process.
1169 * @returns OS/2 / Windows return code
1170 * On successful return (NO_ERROR) the global variables
1171 * pszCmdLineA and pszCmdLineW are set.
1172 *
1173 * @param pszPeExe Pass in the name of the PE exe of this process. We'll
1174 * us this as exename and skip the first argument (ie. argv[1]).
1175 * If NULL we'll use the commandline from OS/2 as it is.
1176 * @status Completely implemented and tested.
1177 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1178 */
1179ULONG InitCommandLine(const char *pszPeExe)
1180{
1181 PCHAR pib_pchcmd; /* PIB pointer to commandline. */
1182 CHAR szFilename[CCHMAXPATH]; /* Filename buffer used to get the exe filename in. */
1183 ULONG cch; /* Commandline string length. (including terminator) */
1184 PSZ psz; /* Temporary string pointer. */
1185 PSZ psz2; /* Temporary string pointer. */
1186 APIRET rc; /* OS/2 return code. */
1187 BOOL fQuotes; /* Flag used to remember if the exe filename should be in quotes. */
1188
1189 /** @sketch
1190 * Get commandline from the PIB.
1191 */
1192 pib_pchcmd = (PCHAR)OSLibGetPIB(PIB_PCHCMD);
1193
1194 /** @sketch
1195 * Two methods of making the commandline:
1196 * (1) The first argument is skipped and the second is used as exe filname.
1197 * This applies to PE.EXE launched processes only.
1198 * (2) No skipping. First argument is the exe filename.
1199 * This applies to all but PE.EXE launched processes.
1200 *
1201 * Note: We could do some code size optimization here. Much of the code for
1202 * the two methods are nearly identical.
1203 *
1204 */
1205 if(pszPeExe)
1206 {
1207 /** @sketch
1208 * Allocate memory for the commandline.
1209 * Build commandline:
1210 * Copy exe filename.
1211 * Add arguments.
1212 */
1213 cch = strlen(pszPeExe)+1;
1214
1215 // PH 2002-04-11
1216 // Note: intentional memory leak, pszCmdLineW will not be freed
1217 // or allocated after process startup
1218 pszCmdLineA = psz = (PSZ)malloc(cch);
1219 if (psz == NULL)
1220 {
1221 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed\n", pszPeExe, cch));
1222 return ERROR_NOT_ENOUGH_MEMORY;
1223 }
1224 strcpy((char *)pszCmdLineA, pszPeExe);
1225
1226 rc = NO_ERROR;
1227 }
1228 else
1229 {
1230 /** @sketch Method (2):
1231 * First we'll have to determin the size of the commandline.
1232 *
1233 * As we don't assume that OS/2 allways puts a fully qualified EXE name
1234 * as the first string, we'll check if it's empty - and get the modulename
1235 * in that case - and allways get the fully qualified filename.
1236 */
1237 if (pib_pchcmd == NULL || pib_pchcmd[0] == '\0')
1238 {
1239 rc = OSLibDosQueryModuleName(OSLibGetPIB(PIB_HMTE), sizeof(szFilename), szFilename);
1240 if (rc != NO_ERROR)
1241 {
1242 dprintf(("KERNEL32: InitCommandLine(%p): OSLibQueryModuleName(0x%x,...) failed with rc=%d\n",
1243 pszPeExe, OSLibGetPIB(PIB_HMTE), rc));
1244 return rc;
1245 }
1246 }
1247 else
1248 {
1249 rc = OSLibDosQueryPathInfo(pib_pchcmd, FIL_QUERYFULLNAME, szFilename, sizeof(szFilename));
1250 if (rc != NO_ERROR)
1251 {
1252 dprintf(("KERNEL32: InitCommandLine(%p): (info) OSLibDosQueryPathInfo failed with rc=%d\n", pszPeExe, rc));
1253 strcpy(szFilename, pib_pchcmd);
1254 rc = NO_ERROR;
1255 }
1256 }
1257
1258 /** @sketch
1259 * We're still measuring the size of the commandline:
1260 * Check if we have to quote the exe filename.
1261 * Determin the length of the executable name including quotes and '\0'-terminator.
1262 * Count the length of the arguments. (We here count's all argument strings.)
1263 */
1264 fQuotes = strchr(szFilename, ' ') != NULL;
1265 cch = strlen(szFilename) + fQuotes*2 + 1;
1266 if (pib_pchcmd != NULL)
1267 {
1268 psz2 = pib_pchcmd + strlen(pib_pchcmd) + 1;
1269 while (*psz2 != '\0')
1270 {
1271 register int cchTmp = strlen(psz2) + 1; /* + 1 is for terminator (psz2) and space (cch). */
1272 psz2 += cchTmp;
1273 cch += cchTmp;
1274 }
1275 }
1276
1277 /** @sketch
1278 * Allocate memory for the commandline.
1279 * Build commandline:
1280 * Copy exe filename.
1281 * Add arguments.
1282 */
1283 pszCmdLineA = psz = (PSZ)malloc(cch);
1284 if (psz == NULL)
1285 {
1286 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed\n", pszPeExe, cch));
1287 return ERROR_NOT_ENOUGH_MEMORY;
1288 }
1289
1290 if (fQuotes)
1291 *psz++ = '"';
1292 strcpy(psz, szFilename);
1293 psz += strlen(psz);
1294 if (fQuotes)
1295 {
1296 *psz++ = '"';
1297 *psz = '\0';
1298 }
1299
1300 if (pib_pchcmd != NULL)
1301 {
1302 psz2 = pib_pchcmd + strlen(pib_pchcmd) + 1;
1303 while (*psz2 != '\0')
1304 {
1305 register int cchTmp = strlen(psz2) + 1; /* + 1 is for terminator (psz). */
1306 *psz++ = ' '; /* add space */
1307 memcpy(psz, psz2, cchTmp);
1308 psz2 += cchTmp;
1309 psz += cchTmp - 1;
1310 }
1311 }
1312 }
1313
1314 /** @sketch
1315 * If successfully build ASCII commandline then convert it to UniCode.
1316 */
1317 if (rc == NO_ERROR)
1318 {
1319 // PH 2002-04-11
1320 // Note: intentional memory leak, pszCmdLineW will not be freed
1321 // or allocated after process startup
1322 pszCmdLineW = (WCHAR*)malloc(cch * 2);
1323 if (pszCmdLineW != NULL)
1324 AsciiToUnicode(pszCmdLineA, (WCHAR*)pszCmdLineW);
1325 else
1326 {
1327 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed (2)\n", pszPeExe, cch));
1328 rc = ERROR_NOT_ENOUGH_MEMORY;
1329 }
1330 }
1331
1332 return rc;
1333}
1334
1335/**
1336 * Gets the command line of the current process.
1337 * @returns On success:
1338 * Command line of the current process. One single string.
1339 * The first part of the command line string is the executable filename
1340 * of the current process. It might be in quotes if it contains spaces.
1341 * The rest of the string is arguments.
1342 *
1343 * On error:
1344 * NULL. Last error set. (does Win32 set last error this?)
1345 * @sketch IF not inited THEN
1346 * Init commandline assuming !PE.EXE
1347 * IF init failes THEN set last error.
1348 * ENDIF
1349 * return ASCII/ANSI commandline.
1350 * @status Completely implemented and tested.
1351 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1352 * @remark The Ring-3 PeLdr is resposible for calling InitCommandLine before anyone
1353 * is able to call this function.
1354 */
1355LPCSTR WIN32API GetCommandLineA(VOID)
1356{
1357 /*
1358 * Check if the commandline is initiated.
1359 * If not we'll have to do it.
1360 * ASSUMES that if not inited this isn't a PE.EXE lauched process.
1361 */
1362 if (pszCmdLineA == NULL)
1363 {
1364 APIRET rc;
1365 rc = InitCommandLine(NULL);
1366 if (rc != NULL)
1367 SetLastError(rc);
1368 }
1369
1370 dprintf(("KERNEL32: GetCommandLineA: %s\n", pszCmdLineA));
1371 return pszCmdLineA;
1372}
1373
1374
1375/**
1376 * Gets the command line of the current process.
1377 * @returns On success:
1378 * Command line of the current process. One single string.
1379 * The first part of the command line string is the executable filename
1380 * of the current process. It might be in quotes if it contains spaces.
1381 * The rest of the string is arguments.
1382 *
1383 * On error:
1384 * NULL. Last error set. (does Win32 set last error this?)
1385 * @sketch IF not inited THEN
1386 * Init commandline assuming !PE.EXE
1387 * IF init failes THEN set last error.
1388 * ENDIF
1389 * return Unicode commandline.
1390 * @status Completely implemented and tested.
1391 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1392 * @remark The Ring-3 PeLdr is resposible for calling InitCommandLine before anyone
1393 * is able to call this function.
1394 */
1395LPCWSTR WIN32API GetCommandLineW(void)
1396{
1397 /*
1398 * Check if the commandline is initiated.
1399 * If not we'll have to do it.
1400 * ASSUMES that if not inited this isn't a PE.EXE lauched process.
1401 */
1402 if (pszCmdLineW == NULL)
1403 {
1404 APIRET rc;
1405 rc = InitCommandLine(NULL);
1406 if (rc != NULL)
1407 SetLastError(rc);
1408 }
1409
1410 dprintf(("KERNEL32: GetCommandLineW: %s\n", pszCmdLineA));
1411 return pszCmdLineW;
1412}
1413
1414
1415/**
1416 * GetModuleFileName gets the full path and file name for the specified module.
1417 * @returns Bytes written to the buffer (lpszPath). This count includes the
1418 * terminating '\0'.
1419 * On error 0 is returned. Last error is set.
1420 *
1421 * 2002-04-25 PH
1422 * Q - Do we set ERROR_BUFFER_OVERFLOW when cch > cchPath?
1423 * Q - Does NT really set the last error?
1424 * A > Win2k does not set LastError here, remains OK
1425 *
1426 * While GetModuleFileName does add a trailing termination zero
1427 * if there is enough room, the returned number of characters
1428 * *MUST NOT* include the zero character!
1429 * (Notes R6 Installer on Win2kSP6, verified Testcase)
1430 *
1431 * @param hModule Handle to the module you like to get the file name to.
1432 * @param lpszPath Output buffer for full path and file name.
1433 * @param cchPath Size of the lpszPath buffer.
1434 * @sketch Validate lpszPath.
1435 * Find the module object using handle.
1436 * If found Then
1437 * Get full path from module object.
1438 * If found path Then
1439 * Copy path to buffer and set the number of bytes written.
1440 * Else
1441 * IPE!
1442 * Else
1443 * Call Open32 GetModuleFileName. (kernel32 initterm needs/needed this)
1444 * Log result.
1445 * Return number of bytes written to the buffer.
1446 *
1447 * @status Completely implemented, Open32.
1448 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1449 * Sander van Leeuwen (sandervl@xs4all.nl)
1450 * Patrick Haller (patrick.haller@innotek.de)
1451 * @remark - Do we still have to call Open32?
1452 */
1453DWORD WIN32API GetModuleFileNameA(HMODULE hModule, LPTSTR lpszPath, DWORD cchPath)
1454{
1455 Win32ImageBase * pMod; /* Pointer to the module object. */
1456 DWORD cch = 0; /* Length of the */
1457
1458 // PH 2002-04-24 Note:
1459 // WIN2k just crashes in NTDLL if lpszPath is invalid!
1460 if (!VALID_PSZ(lpszPath))
1461 {
1462 dprintf(("KERNEL32: GetModuleFileNameA(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
1463 hModule, lpszPath, cchPath, lpszPath));
1464 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
1465 return 0;
1466 }
1467
1468 pMod = Win32ImageBase::findModule(hModule);
1469 if (pMod != NULL)
1470 {
1471 const char *pszFn = pMod->getFullPath();
1472 if (pszFn)
1473 {
1474 cch = strlen(pszFn);
1475 if (cch >= cchPath)
1476 cch = cchPath;
1477 else
1478 // if there is sufficient room for the zero termination,
1479 // write it additionally, uncounted
1480 lpszPath[cch] = '\0';
1481
1482 memcpy(lpszPath, pszFn, cch);
1483 }
1484 else
1485 {
1486 dprintf(("KERNEL32: GetModuleFileNameA(%x,...): IPE - getFullPath returned NULL or empty string\n"));
1487 DebugInt3();
1488 SetLastError(ERROR_INVALID_HANDLE);
1489 }
1490 }
1491 else
1492 {
1493 SetLastError(ERROR_INVALID_HANDLE);
1494 //only needed for call inside kernel32's initterm (profile init)
1495 //(console init only it seems...)
1496 cch = OSLibDosGetModuleFileName(hModule, lpszPath, cchPath);
1497 }
1498
1499 if (cch > 0)
1500 dprintf(("KERNEL32: GetModuleFileNameA(%x %x): %s %d\n", hModule, lpszPath, lpszPath, cch));
1501 else
1502 dprintf(("KERNEL32: WARNING: GetModuleFileNameA(%x,...) - not found!", hModule));
1503
1504 return cch;
1505}
1506
1507
1508/**
1509 * GetModuleFileName gets the full path and file name for the specified module.
1510 * @returns Bytes written to the buffer (lpszPath). This count includes the
1511 * terminating '\0'.
1512 * On error 0 is returned. Last error is set.
1513 * @param hModule Handle to the module you like to get the file name to.
1514 * @param lpszPath Output buffer for full path and file name.
1515 * @param cchPath Size of the lpszPath buffer.
1516 * @sketch Find the module object using handle.
1517 * If found Then
1518 * get full path from module object.
1519 * If found path Then
1520 * Determin path length.
1521 * Translate the path to into the buffer.
1522 * Else
1523 * IPE.
1524 * else
1525 * SetLastError to invalid handle.
1526 * Log result.
1527 * return number of bytes written to the buffer.
1528 *
1529 * @status Completely implemented.
1530 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1531 * @remark - We do _NOT_ call Open32.
1532 * - Do we set ERROR_BUFFER_OVERFLOW when cch > cchPath?
1533 * - Does NT really set the last error?
1534 */
1535DWORD WIN32API GetModuleFileNameW(HMODULE hModule, LPWSTR lpszPath, DWORD cchPath)
1536{
1537 Win32ImageBase * pMod;
1538 DWORD cch = 0;
1539
1540 if (!VALID_PSZ(lpszPath))
1541 {
1542 dprintf(("KERNEL32: GetModuleFileNameW(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
1543 hModule, lpszPath, cchPath, lpszPath));
1544 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
1545 return 0;
1546 }
1547
1548 pMod = Win32ImageBase::findModule(hModule);
1549 if (pMod != NULL)
1550 {
1551 const char *pszFn = pMod->getFullPath();
1552 if (pszFn || *pszFn != '\0')
1553 {
1554 cch = strlen(pszFn) + 1;
1555 if (cch > cchPath)
1556 cch = cchPath;
1557 AsciiToUnicodeN(pszFn, lpszPath, cch);
1558 }
1559 else
1560 {
1561 dprintf(("KERNEL32: GetModuleFileNameW(%x,...): IPE - getFullPath returned NULL or empty string\n"));
1562 DebugInt3();
1563 SetLastError(ERROR_INVALID_HANDLE);
1564 }
1565 }
1566 else
1567 SetLastError(ERROR_INVALID_HANDLE);
1568
1569 if (cch > 0)
1570 dprintf(("KERNEL32: GetModuleFileNameW(%x,...): %s %d\n", hModule, lpszPath, cch));
1571 else
1572 dprintf(("KERNEL32: WARNING: GetModuleFileNameW(%x,...) - not found!", hModule));
1573
1574 return cch;
1575}
1576
1577
1578//******************************************************************************
1579//NOTE: GetModuleHandleA does NOT support files with multiple dots (i.e.
1580// very.weird.exe)
1581//
1582// hinst = LoadLibrary("WINSPOOL.DRV"); -> succeeds
1583// hinst2 = GetModuleHandle("WINSPOOL.DRV"); -> succeeds
1584// hinst3 = GetModuleHandle("WINSPOOL."); -> fails
1585// hinst4 = GetModuleHandle("WINSPOOL"); -> fails
1586// hinst = LoadLibrary("KERNEL32.DLL"); -> succeeds
1587// hinst2 = GetModuleHandle("KERNEL32.DLL"); -> succeeds
1588// hinst3 = GetModuleHandle("KERNEL32."); -> fails
1589// hinst4 = GetModuleHandle("KERNEL32"); -> succeeds
1590// Same behaviour as observed in NT4, SP6
1591//******************************************************************************
1592HANDLE WIN32API GetModuleHandleA(LPCTSTR lpszModule)
1593{
1594 HANDLE hMod = 0;
1595 Win32DllBase *windll;
1596 char szModule[CCHMAXPATH];
1597 char *dot;
1598
1599 if(lpszModule == NULL)
1600 {
1601 if(WinExe)
1602 hMod = WinExe->getInstanceHandle();
1603 else
1604 {
1605 // // Just fail this API
1606 // hMod = 0;
1607 // SetLastError(ERROR_INVALID_HANDLE);
1608 // Wrong: in an ODIN32-LX environment, just
1609 // assume a fake handle
1610 hMod = -1;
1611 }
1612 }
1613 else
1614 {
1615 strcpy(szModule, OSLibStripPath((char *)lpszModule));
1616 strupr(szModule);
1617 dot = strchr(szModule, '.');
1618 if(dot == NULL) {
1619 //if no extension -> add .DLL (see SDK docs)
1620 strcat(szModule, DLL_EXTENSION);
1621 }
1622 else {
1623 if(dot[1] == 0) {
1624 //a trailing dot means the module has no extension (SDK docs)
1625 *dot = 0;
1626 }
1627 }
1628 if(WinExe && WinExe->matchModName(szModule)) {
1629 hMod = WinExe->getInstanceHandle();
1630 }
1631 else {
1632 windll = Win32DllBase::findModule(szModule);
1633 if(windll) {
1634 hMod = windll->getInstanceHandle();
1635 }
1636 }
1637 }
1638 dprintf(("KERNEL32: GetModuleHandle %s returned %X\n", lpszModule, hMod));
1639 return(hMod);
1640}
1641//******************************************************************************
1642//******************************************************************************
1643HMODULE WIN32API GetModuleHandleW(LPCWSTR lpwszModuleName)
1644{
1645 HMODULE rc;
1646 char *astring = NULL;
1647
1648 if (NULL != lpwszModuleName)
1649 astring = UnicodeToAsciiString((LPWSTR)lpwszModuleName);
1650
1651 rc = GetModuleHandleA(astring);
1652 dprintf(("KERNEL32: OS2GetModuleHandleW %s returned %X\n", astring, rc));
1653
1654 if (NULL != astring)
1655 FreeAsciiString(astring);
1656
1657 return(rc);
1658}
1659//******************************************************************************
1660//******************************************************************************
1661BOOL WINAPI CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine,
1662 LPSECURITY_ATTRIBUTES lpProcessAttributes,
1663 LPSECURITY_ATTRIBUTES lpThreadAttributes,
1664 BOOL bInheritHandles, DWORD dwCreationFlags,
1665 LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
1666 LPSTARTUPINFOA lpStartupInfo,
1667 LPPROCESS_INFORMATION lpProcessInfo )
1668{
1669 TEB *pThreadDB = (TEB*)GetThreadTEB();
1670 char *cmdline = NULL;
1671 BOOL rc;
1672
1673 dprintf(("KERNEL32: CreateProcessA %s cline:%s inherit:%d cFlags:%x Env:%x CurDir:%s StartupFlags:%x\n",
1674 lpApplicationName, lpCommandLine, bInheritHandles, dwCreationFlags,
1675 lpEnvironment, lpCurrentDirectory, lpStartupInfo));
1676
1677#ifdef DEBUG
1678 if(lpStartupInfo) {
1679 dprintf(("lpStartupInfo->lpReserved %x", lpStartupInfo->lpReserved));
1680 dprintf(("lpStartupInfo->lpDesktop %x", lpStartupInfo->lpDesktop));
1681 dprintf(("lpStartupInfo->lpTitle %s", lpStartupInfo->lpTitle));
1682 dprintf(("lpStartupInfo->dwX %x", lpStartupInfo->dwX));
1683 dprintf(("lpStartupInfo->dwY %x", lpStartupInfo->dwY));
1684 dprintf(("lpStartupInfo->dwXSize %x", lpStartupInfo->dwXSize));
1685 dprintf(("lpStartupInfo->dwYSize %x", lpStartupInfo->dwYSize));
1686 dprintf(("lpStartupInfo->dwXCountChars %x", lpStartupInfo->dwXCountChars));
1687 dprintf(("lpStartupInfo->dwYCountChars %x", lpStartupInfo->dwYCountChars));
1688 dprintf(("lpStartupInfo->dwFillAttribute %x", lpStartupInfo->dwFillAttribute));
1689 dprintf(("lpStartupInfo->dwFlags %x", lpStartupInfo->dwFlags));
1690 dprintf(("lpStartupInfo->wShowWindow %x", lpStartupInfo->wShowWindow));
1691 dprintf(("lpStartupInfo->hStdInput %x", lpStartupInfo->hStdInput));
1692 dprintf(("lpStartupInfo->hStdOutput %x", lpStartupInfo->hStdOutput));
1693 dprintf(("lpStartupInfo->hStdError %x", lpStartupInfo->hStdError));
1694 }
1695#endif
1696
1697 // open32 does not support DEBUG_ONLY_THIS_PROCESS
1698 if(dwCreationFlags & DEBUG_ONLY_THIS_PROCESS)
1699 dwCreationFlags |= DEBUG_PROCESS;
1700
1701 if(O32_CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes,
1702 lpThreadAttributes, bInheritHandles, dwCreationFlags,
1703 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
1704 lpProcessInfo) == TRUE)
1705 {
1706 if (dwCreationFlags & DEBUG_PROCESS && pThreadDB != NULL)
1707 {
1708 if(pThreadDB->o.odin.pidDebuggee != 0)
1709 {
1710 // TODO: handle this
1711 dprintf(("KERNEL32: CreateProcess ERROR: This thread is already a debugger\n"));
1712 }
1713 else
1714 {
1715 pThreadDB->o.odin.pidDebuggee = lpProcessInfo->dwProcessId;
1716 OSLibStartDebugger((ULONG*)&pThreadDB->o.odin.pidDebuggee);
1717 }
1718 }
1719 else pThreadDB->o.odin.pidDebuggee = 0;
1720
1721 return(TRUE);
1722 }
1723
1724 // PH 2001-05-07
1725 // verify why O32_CreateProcess actually failed.
1726 // If GetLastError() == 191 (ERROR_INVALID_EXE_SIGNATURE)
1727 // we can continue to call "PE.EXE".
1728 // Note: Open32 does not translate ERROR_INVALID_EXE_SIGNATURE,
1729 // it is also valid in Win32.
1730 DWORD dwError = GetLastError();
1731 if (ERROR_INVALID_EXE_SIGNATURE != dwError && ERROR_FILE_NOT_FOUND != dwError && ERROR_ACCESS_DENIED != dwError)
1732 {
1733 dprintf(("CreateProcess: O32_CreateProcess failed with rc=%d, not PE-executable !",
1734 dwError));
1735
1736 // the current value of GetLastError() is still valid.
1737
1738 return FALSE;
1739 }
1740
1741 // else ...
1742
1743 //probably a win32 exe, so run it in the pe loader
1744 if(lpApplicationName) {
1745 if(lpCommandLine) {
1746 //skip exe name in lpCommandLine
1747 //TODO: doesn't work for directories with spaces!
1748 while(*lpCommandLine != 0 && *lpCommandLine != ' ')
1749 lpCommandLine++;
1750
1751 if(*lpCommandLine != 0) {
1752 lpCommandLine++;
1753 }
1754 cmdline = (char *)malloc(strlen(lpApplicationName)+strlen(lpCommandLine) + 16);
1755 sprintf(cmdline, "%s %s", lpApplicationName, lpCommandLine);
1756 }
1757 else {
1758 cmdline = (char *)malloc(strlen(lpApplicationName) + 16);
1759 sprintf(cmdline, "%s", lpApplicationName);
1760 }
1761 }
1762 else {
1763 cmdline = (char *)malloc(strlen(lpCommandLine) + 16);
1764 sprintf(cmdline, "%s", lpCommandLine);
1765 }
1766
1767 char szAppName[MAX_PATH];
1768 char buffer[MAX_PATH];
1769 DWORD fileAttr;
1770 char *exename = buffer;
1771 strncpy(buffer, cmdline, sizeof(szAppName));
1772 buffer[MAX_PATH-1] = 0;
1773 if(*exename == '"') {
1774 exename++;
1775 while(*exename != 0 && *exename != '"')
1776 exename++;
1777
1778 if(*exename != 0) {
1779 *exename = 0;
1780 }
1781 exename++;
1782 if (SearchPathA( NULL, &buffer[1], ".exe", sizeof(szAppName), szAppName, NULL ) ||
1783 SearchPathA( NULL, &buffer[1], NULL, sizeof(szAppName), szAppName, NULL ))
1784 {
1785 //
1786 }
1787 }
1788 else {
1789 BOOL fTerminate = FALSE;
1790 DWORD fileAttr;
1791
1792 while(*exename != 0) {
1793 while(*exename != 0 && *exename != ' ')
1794 exename++;
1795
1796 if(*exename != 0) {
1797 *exename = 0;
1798 fTerminate = TRUE;
1799 }
1800 dprintf(("Trying '%s'", buffer ));
1801 if (SearchPathA( NULL, buffer, ".exe", sizeof(szAppName), szAppName, NULL ) ||
1802 SearchPathA( NULL, buffer, NULL, sizeof(szAppName), szAppName, NULL ))
1803 {
1804 if(fTerminate) exename++;
1805 break;
1806 }
1807
1808 if(fTerminate) {
1809 *exename = ' ';
1810 exename++;
1811 fTerminate = FALSE;
1812 }
1813 }
1814 }
1815 lpCommandLine = exename; //start of command line parameters
1816
1817 fileAttr = GetFileAttributesA(szAppName);
1818 if(fileAttr == -1 || (fileAttr & FILE_ATTRIBUTE_DIRECTORY)) {
1819 dprintf(("CreateProcess: can't find executable!"));
1820 SetLastError(ERROR_FILE_NOT_FOUND);
1821 return FALSE;
1822 }
1823
1824 dprintf(("KERNEL32: CreateProcess %s %s", szAppName, lpCommandLine));
1825
1826 DWORD Characteristics, SubSystem, fNEExe;
1827 if(Win32ImageBase::isPEImage(szAppName, &Characteristics, &SubSystem, &fNEExe) == 0)
1828 {
1829 char *lpszPE;
1830 char *lpszExecutable;
1831 int iNewCommandLineLength;
1832
1833 // calculate base length for the new command line
1834 iNewCommandLineLength = strlen(szAppName) + strlen(lpCommandLine);
1835
1836 if(SubSystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
1837 lpszExecutable = "PEC.EXE";
1838 else
1839 lpszExecutable = "PE.EXE";
1840
1841 lpszPE = lpszExecutable;
1842
1843 // 2002-04-24 PH
1844 // set the ODIN32.DEBUG_CHILD environment variable to start new PE processes
1845 // under a new instance of the (IPMD) debugger.
1846#ifdef DEBUG
1847 CHAR debug_szPE[ 512 ];
1848 PSZ debug_pszOS2Debugger = getenv("ODIN32.DEBUG_CHILD");
1849 if (NULL != debug_pszOS2Debugger)
1850 {
1851 // build new start command
1852 strcpy(debug_szPE, debug_pszOS2Debugger);
1853 strcat(debug_szPE, " ");
1854 strcat(debug_szPE, lpszExecutable);
1855
1856 // we require more space in the new command line
1857 iNewCommandLineLength += strlen( debug_szPE );
1858
1859 // only launch the specified executable (ICSDEBUG.EXE)
1860 lpszPE = debug_szPE;
1861 lpszExecutable = debug_pszOS2Debugger;
1862 }
1863#endif
1864
1865 //SvL: Allright. Before we call O32_CreateProcess, we must take care of
1866 // lpCurrentDirectory ourselves. (Open32 ignores it!)
1867 if(lpCurrentDirectory) {
1868 char *newcmdline;
1869
1870 newcmdline = (char *)malloc(strlen(lpCurrentDirectory) + iNewCommandLineLength + 32);
1871 sprintf(newcmdline, "%s /OPT:[CURDIR=%s] %s %s", lpszPE, lpCurrentDirectory, szAppName, lpCommandLine);
1872 free(cmdline);
1873 cmdline = newcmdline;
1874 }
1875 else {
1876 char *newcmdline;
1877
1878 newcmdline = (char *)malloc(iNewCommandLineLength + 16);
1879 sprintf(newcmdline, "%s %s %s", lpszPE, szAppName, lpCommandLine);
1880 free(cmdline);
1881 cmdline = newcmdline;
1882 }
1883
1884 dprintf(("KERNEL32: CreateProcess starting [%s],[%s]",
1885 lpszExecutable,
1886 cmdline));
1887
1888 rc = O32_CreateProcess(lpszExecutable, (LPCSTR)cmdline,lpProcessAttributes,
1889 lpThreadAttributes, bInheritHandles, dwCreationFlags,
1890 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
1891 lpProcessInfo);
1892 }
1893 else
1894 if(fNEExe) {//16 bits windows app
1895 char *newcmdline;
1896
1897 newcmdline = (char *)malloc(strlen(szAppName) + strlen(cmdline) + 16);
1898 sprintf(newcmdline, "w16odin.exe %s", szAppName, lpCommandLine);
1899 free(cmdline);
1900 cmdline = newcmdline;
1901 //Force Open32 to use DosStartSession (DosExecPgm won't do)
1902 dwCreationFlags |= CREATE_NEW_PROCESS_GROUP;
1903 rc = O32_CreateProcess("w16odin.exe", (LPCSTR)cmdline, lpProcessAttributes,
1904 lpThreadAttributes, bInheritHandles, dwCreationFlags,
1905 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
1906 lpProcessInfo);
1907 }
1908 else {//os/2 app??
1909 rc = O32_CreateProcess(szAppName, (LPCSTR)lpCommandLine, lpProcessAttributes,
1910 lpThreadAttributes, bInheritHandles, dwCreationFlags,
1911 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
1912 lpProcessInfo);
1913 }
1914 if(rc == TRUE)
1915 {
1916 if (dwCreationFlags & DEBUG_PROCESS && pThreadDB != NULL)
1917 {
1918 if(pThreadDB->o.odin.pidDebuggee != 0)
1919 {
1920 // TODO: handle this
1921 dprintf(("KERNEL32: CreateProcess ERROR: This thread is already a debugger\n"));
1922 }
1923 else
1924 {
1925 pThreadDB->o.odin.pidDebuggee = lpProcessInfo->dwProcessId;
1926 OSLibStartDebugger((ULONG*)&pThreadDB->o.odin.pidDebuggee);
1927 }
1928 }
1929 else
1930 pThreadDB->o.odin.pidDebuggee = 0;
1931 }
1932 if(cmdline)
1933 free(cmdline);
1934
1935 if(lpProcessInfo)
1936 {
1937 lpProcessInfo->dwThreadId = MAKE_THREADID(lpProcessInfo->dwProcessId, lpProcessInfo->dwThreadId);
1938 dprintf(("KERNEL32: CreateProcess returned %d hPro:%x hThr:%x pid:%x tid:%x\n",
1939 rc, lpProcessInfo->hProcess, lpProcessInfo->hThread,
1940 lpProcessInfo->dwProcessId,lpProcessInfo->dwThreadId));
1941 }
1942 else
1943 dprintf(("KERNEL32: CreateProcess returned %d\n", rc));
1944 return(rc);
1945}
1946//******************************************************************************
1947//******************************************************************************
1948BOOL WIN32API CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
1949 PSECURITY_ATTRIBUTES lpProcessAttributes,
1950 PSECURITY_ATTRIBUTES lpThreadAttributes,
1951 BOOL bInheritHandles, DWORD dwCreationFlags,
1952 LPVOID lpEnvironment,
1953 LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
1954 LPPROCESS_INFORMATION lpProcessInfo)
1955{
1956 BOOL rc;
1957 char *astring1 = 0, *astring2 = 0, *astring3 = 0;
1958
1959 dprintf(("KERNEL32: CreateProcessW"));
1960 if(lpApplicationName)
1961 astring1 = UnicodeToAsciiString((LPWSTR)lpApplicationName);
1962 if(lpCommandLine)
1963 astring2 = UnicodeToAsciiString(lpCommandLine);
1964 if(lpCurrentDirectory)
1965 astring3 = UnicodeToAsciiString((LPWSTR)lpCurrentDirectory);
1966 rc = CreateProcessA(astring1, astring2, lpProcessAttributes, lpThreadAttributes,
1967 bInheritHandles, dwCreationFlags, lpEnvironment,
1968 astring3, (LPSTARTUPINFOA)lpStartupInfo,
1969 lpProcessInfo);
1970 if(astring3) FreeAsciiString(astring3);
1971 if(astring2) FreeAsciiString(astring2);
1972 if(astring1) FreeAsciiString(astring1);
1973 return(rc);
1974}
1975//******************************************************************************
1976//******************************************************************************
1977HINSTANCE WIN32API WinExec(LPCSTR lpCmdLine, UINT nCmdShow)
1978{
1979 STARTUPINFOA startinfo = {0};
1980 PROCESS_INFORMATION procinfo;
1981 DWORD rc;
1982 HINSTANCE hInstance;
1983
1984 dprintf(("KERNEL32: WinExec %s\n", lpCmdLine));
1985 startinfo.dwFlags = nCmdShow;
1986 if(CreateProcessA(NULL, (LPSTR)lpCmdLine, NULL, NULL, FALSE, 0, NULL, NULL,
1987 &startinfo, &procinfo) == FALSE)
1988 {
1989 hInstance = (HINSTANCE)GetLastError();
1990 if(hInstance >= 32) {
1991 hInstance = 11;
1992 }
1993 dprintf(("KERNEL32: WinExec failed with rc %d", hInstance));
1994 return hInstance;
1995 }
1996 //block until the launched app waits for input (or a timeout of 15 seconds)
1997 //TODO: Shouldn't call Open32, but the api in user32..
1998 if(fVersionWarp3) {
1999 Sleep(1000); //WaitForInputIdle not available in Warp 3
2000 }
2001 else {
2002 dprintf(("Calling WaitForInputIdle %x %d", procinfo.hProcess, 15000));
2003 rc = WaitForInputIdle(procinfo.hProcess, 15000);
2004#ifdef DEBUG
2005 if(rc != 0) {
2006 dprintf(("WinExec: WaitForInputIdle %x returned %x", procinfo.hProcess, rc));
2007 }
2008 else dprintf(("WinExec: WaitForInputIdle successfull"));
2009#endif
2010 }
2011 CloseHandle(procinfo.hThread);
2012 CloseHandle(procinfo.hProcess);
2013 return 33;
2014}
2015//******************************************************************************
2016//DWORD idAttach; /* thread to attach */
2017//DWORD idAttachTo; /* thread to attach to */
2018//BOOL fAttach; /* attach or detach */
2019//******************************************************************************
2020BOOL WIN32API AttachThreadInput(DWORD idAttach, DWORD idAttachTo, BOOL fAttach)
2021{
2022 dprintf(("USER32: AttachThreadInput, not implemented\n"));
2023 return(TRUE);
2024}
2025//******************************************************************************
2026//******************************************************************************
2027DWORD WIN32API WaitForInputIdle(HANDLE hProcess, DWORD dwTimeOut)
2028{
2029 dprintf(("USER32: WaitForInputIdle %x %d\n", hProcess, dwTimeOut));
2030
2031 if(fVersionWarp3) {
2032 Sleep(1000);
2033 return 0;
2034 }
2035 else return O32_WaitForInputIdle(hProcess, dwTimeOut);
2036}
2037/**********************************************************************
2038 * LoadModule (KERNEL32.499)
2039 *
2040 * Wine: 20000909
2041 *
2042 * Copyright 1995 Alexandre Julliard
2043 */
2044HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock )
2045{
2046 LOADPARAMS *params = (LOADPARAMS *)paramBlock;
2047 PROCESS_INFORMATION info;
2048 STARTUPINFOA startup;
2049 HINSTANCE hInstance;
2050 LPSTR cmdline, p;
2051 char filename[MAX_PATH];
2052 BYTE len;
2053
2054 dprintf(("LoadModule %s %x", name, paramBlock));
2055
2056 if (!name) return ERROR_FILE_NOT_FOUND;
2057
2058 if (!SearchPathA( NULL, name, ".exe", sizeof(filename), filename, NULL ) &&
2059 !SearchPathA( NULL, name, NULL, sizeof(filename), filename, NULL ))
2060 return GetLastError();
2061
2062 len = (BYTE)params->lpCmdLine[0];
2063 if (!(cmdline = (LPSTR)HeapAlloc( GetProcessHeap(), 0, strlen(filename) + len + 2 )))
2064 return ERROR_NOT_ENOUGH_MEMORY;
2065
2066 strcpy( cmdline, filename );
2067 p = cmdline + strlen(cmdline);
2068 *p++ = ' ';
2069 memcpy( p, params->lpCmdLine + 1, len );
2070 p[len] = 0;
2071
2072 memset( &startup, 0, sizeof(startup) );
2073 startup.cb = sizeof(startup);
2074 if (params->lpCmdShow)
2075 {
2076 startup.dwFlags = STARTF_USESHOWWINDOW;
2077 startup.wShowWindow = params->lpCmdShow[1];
2078 }
2079
2080 if (CreateProcessA( filename, cmdline, NULL, NULL, FALSE, 0,
2081 params->lpEnvAddress, NULL, &startup, &info ))
2082 {
2083 /* Give 15 seconds to the app to come up */
2084 if ( WaitForInputIdle ( info.hProcess, 15000 ) == 0xFFFFFFFF )
2085 dprintf(("ERROR: WaitForInputIdle failed: Error %ld\n", GetLastError() ));
2086 hInstance = 33;
2087 /* Close off the handles */
2088 CloseHandle( info.hThread );
2089 CloseHandle( info.hProcess );
2090 }
2091 else if ((hInstance = GetLastError()) >= 32)
2092 {
2093 dprintf(("ERROR: Strange error set by CreateProcess: %d\n", hInstance ));
2094 hInstance = 11;
2095 }
2096
2097 HeapFree( GetProcessHeap(), 0, cmdline );
2098 return hInstance;
2099}
2100//******************************************************************************
2101//******************************************************************************
2102FARPROC WIN32API GetProcAddress(HMODULE hModule, LPCSTR lpszProc)
2103{
2104 Win32ImageBase *winmod;
2105 FARPROC proc;
2106 ULONG ulAPIOrdinal;
2107
2108 if(hModule == 0 || hModule == -1 || (WinExe && hModule == WinExe->getInstanceHandle())) {
2109 winmod = WinExe;
2110 }
2111 else winmod = (Win32ImageBase *)Win32DllBase::findModule((HINSTANCE)hModule);
2112
2113 if(winmod) {
2114 ulAPIOrdinal = (ULONG)lpszProc;
2115 if (ulAPIOrdinal <= 0x0000FFFF) {
2116 proc = (FARPROC)winmod->getApi((int)ulAPIOrdinal);
2117 }
2118 else proc = (FARPROC)winmod->getApi((char *)lpszProc);
2119 if(proc == 0) {
2120#ifdef DEBUG
2121 if(ulAPIOrdinal <= 0x0000FFFF) {
2122 dprintf(("GetProcAddress %x %x not found!", hModule, ulAPIOrdinal));
2123 }
2124 else dprintf(("GetProcAddress %x %s not found!", hModule, lpszProc));
2125#endif
2126 SetLastError(ERROR_PROC_NOT_FOUND);
2127 }
2128 if(HIWORD(lpszProc))
2129 dprintf(("KERNEL32: GetProcAddress %s from %X returned %X\n", lpszProc, hModule, proc));
2130 else dprintf(("KERNEL32: GetProcAddress %x from %X returned %X\n", lpszProc, hModule, proc));
2131
2132 SetLastError(ERROR_SUCCESS);
2133 return proc;
2134 }
2135 proc = (FARPROC)OSLibDosGetProcAddress(hModule, lpszProc);
2136 if(HIWORD(lpszProc))
2137 dprintf(("KERNEL32: GetProcAddress %s from %X returned %X\n", lpszProc, hModule, proc));
2138 else dprintf(("KERNEL32: GetProcAddress %x from %X returned %X\n", lpszProc, hModule, proc));
2139 SetLastError(ERROR_SUCCESS);
2140 return(proc);
2141}
2142//******************************************************************************
2143//Retrieve the version
2144//******************************************************************************
2145BOOL SYSTEM GetVersionStruct(char *lpszModName, char *verstruct, ULONG bufLength)
2146{
2147 Win32ImageBase *winimage;
2148 HINSTANCE hDll;
2149 BOOL rc = FALSE;
2150
2151 dprintf(("GetVersionStruct of module %s %x %d", lpszModName, verstruct, bufLength));
2152 if(verstruct == NULL) {
2153 SetLastError(ERROR_INVALID_PARAMETER);
2154 return FALSE;
2155 }
2156 if (WinExe != NULL && WinExe->matchModName(lpszModName)) {
2157 return WinExe->getVersionStruct(verstruct, bufLength);
2158 }
2159 hDll = LoadLibraryExA(lpszModName, 0, LOAD_LIBRARY_AS_DATAFILE);
2160 if(hDll == 0) {
2161 dprintf(("ERROR: GetVersionStruct: Unable to load module!!"));
2162 return 0;
2163 }
2164 winimage = (Win32ImageBase *)Win32DllBase::findModule(hDll);
2165 if(winimage != NULL) {
2166 rc = winimage->getVersionStruct(verstruct, bufLength);
2167 }
2168 else {
2169 dprintf(("GetVersionStruct; just loaded dll %s, but can't find it now!", lpszModName));
2170//// DebugInt3();
2171 }
2172 FreeLibrary(hDll);
2173 return rc;
2174}
2175//******************************************************************************
2176//******************************************************************************
2177ULONG SYSTEM GetVersionSize(char *lpszModName)
2178{
2179 Win32ImageBase *winimage;
2180 HINSTANCE hDll;
2181 ULONG size = 0;
2182
2183 dprintf(("GetVersionSize of %s", lpszModName));
2184 if (WinExe != NULL && WinExe->matchModName(lpszModName)) {
2185 return WinExe->getVersionSize();
2186 }
2187
2188 hDll = LoadLibraryExA(lpszModName, 0, LOAD_LIBRARY_AS_DATAFILE);
2189 if(hDll == 0) {
2190 dprintf(("ERROR: GetVersionStruct: Unable to load module!!"));
2191 return 0;
2192 }
2193 winimage = (Win32ImageBase *)Win32DllBase::findModule(hDll);
2194 if(winimage != NULL) {
2195 size = winimage->getVersionSize();
2196 }
2197 else {
2198 dprintf(("GetVersionSize; just loaded dll %s, but can't find it now!", lpszModName));
2199//// DebugInt3();
2200 }
2201 FreeLibrary(hDll);
2202 return size;
2203}
2204//******************************************************************************
2205//******************************************************************************
2206BOOL WIN32API DisableThreadLibraryCalls(HMODULE hModule)
2207{
2208 Win32DllBase *winmod;
2209 FARPROC proc;
2210 ULONG ulAPIOrdinal;
2211
2212 winmod = Win32DllBase::findModule((HINSTANCE)hModule);
2213 if(winmod)
2214 {
2215 // don't call ATTACH/DETACH thread functions in DLL
2216 winmod->disableThreadLibraryCalls();
2217 return TRUE;
2218 }
2219 else
2220 {
2221 // raise error condition
2222 SetLastError(ERROR_INVALID_HANDLE);
2223 return FALSE;
2224 }
2225}
2226//******************************************************************************
2227//******************************************************************************
Note: See TracBrowser for help on using the repository browser.