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

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

LoadLibraryExA: expand library filename; might contain environment variables

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