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

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

Removed: LoadLibraryExA: expand library filename (doesn't happen in Windows)

File size: 83.5 KB
Line 
1/* $Id: wprocess.cpp,v 1.155 2002-06-16 08:20:36 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 /** @sketch
792 * First we'll see if the module is allready loaded - either as the EXE or as DLL.
793 * IF Executable present AND libfile matches the modname of the executable THEN
794 * RETURN instance handle of executable.
795 * Endif
796 * IF allready loaded THEN
797 * IF it's a LX dll which isn't loaded and we're using the PeLoader THEN
798 * Set Load library.
799 * Endif
800 * Inc dynamic reference count.
801 * Inc reference count.
802 * RETURN instance handle.
803 * Endif
804 */
805 strcpy(szModname, lpszLibFile);
806 strupr(szModname);
807 dot = strchr(szModname, '.');
808 if(dot == NULL) {
809 //if there's no extension or trainling dot, we
810 //assume it's a dll (see Win32 SDK docs)
811 strcat(szModname, DLL_EXTENSION);
812 }
813 else {
814 if(dot[1] == 0) {
815 //a trailing dot means the module has no extension (SDK docs)
816 *dot = 0;
817 }
818 }
819 if (WinExe != NULL && WinExe->matchModName(szModname))
820 return WinExe->getInstanceHandle();
821
822 pModule = Win32DllBase::findModule((LPSTR)szModname);
823 if (pModule)
824 {
825 pModule->incDynamicLib();
826 pModule->AddRef();
827 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Dll found %s",
828 szModname, hFile, dwFlags, pModule->getInstanceHandle(), pModule->getFullPath()));
829 return pModule->getInstanceHandle();
830 }
831
832
833 /** @sketch
834 * Test if lpszLibFile has a path or not.
835 * Copy the lpszLibFile to szModname, rename the dll and uppercase the name.
836 * IF it hasn't a path THEN
837 * Issue a findDll to find the dll/executable to be loaded.
838 * IF the Dll isn't found THEN
839 * Set last error and RETURN.
840 * Endif.
841 * Endif
842 */
843 fPath = strchr(szModname, '\\') || strchr(szModname, '/');
844 Win32DllBase::renameDll(szModname);
845
846 if (!fPath)
847 {
848 char szModName2[CCHMAXPATH];
849 strcpy(szModName2, szModname);
850 if (!Win32ImageBase::findDll(szModName2, szModname, sizeof(szModname)))
851 {
852 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): module wasn't found. returns NULL",
853 lpszLibFile, hFile, dwFlags));
854 SetLastError(ERROR_FILE_NOT_FOUND);
855 return NULL;
856 }
857 }
858
859 //test if dll is in PE or LX format
860 fPE = Win32ImageBase::isPEImage(szModname, &Characteristics, NULL);
861
862 /** @sketch
863 * IF (!fPeLoader || fPE == failure) THEN
864 * Try load the executable using LoadLibrary
865 * IF successfully loaded THEN
866 * IF LX dll and is using the PE Loader THEN
867 * Set Load library.
868 * Inc reference count.
869 * Endif
870 * Inc dynamic reference count.
871 * RETURN successfully.
872 * Endif
873 * Endif
874 */
875 //only call OS/2 if LX binary or win32k process
876 if (!fPeLoader || fPE != ERROR_SUCCESS)
877 {
878 hDll = OSLibDosLoadModule(szModname);
879 if (hDll)
880 {
881 /* OS/2 dll, system dll, converted dll or win32k took care of it. */
882 pModule = Win32DllBase::findModuleByOS2Handle(hDll);
883 if (pModule)
884 {
885 if (pModule->isLxDll())
886 {
887 ((Win32LxDll *)pModule)->setDllHandleOS2(hDll);
888 if (fPeLoader && pModule->AddRef() == -1)
889 { //-1 -> load failed (attachProcess)
890 delete pModule;
891 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
892 dprintf(("Dll %s refused to be loaded; aborting", szModname));
893 return 0;
894 }
895
896 }
897 pModule->incDynamicLib();
898 }
899 else if (fExeStarted && !fIsOS2Image) {
900 OSLibDosFreeModule(hDll);
901 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
902 dprintf(("Dll %s is not an Odin dll; unload & return failure", szModname));
903 return 0;
904 }
905 else {
906 /* bird 2001-07-10:
907 * let's fail right away instead of hitting DebugInt3s and fail other places.
908 * This is very annoying when running Opera on a debug build with netscape/2
909 * plugins present. We'll make this conditional for the time being.
910 */
911 static BOOL fFailIfUnregisteredLX = -1;
912 if (fFailIfUnregisteredLX == -1)
913 fFailIfUnregisteredLX = getenv("ODIN32.FAIL_IF_UNREGISTEREDLX") != NULL;
914 if (fExeStarted && fFailIfUnregisteredLX)
915 {
916 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Loaded OS/2 dll %s using DosLoadModule. returns NULL.",
917 lpszLibFile, hFile, dwFlags, hDll, szModname));
918 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
919 return NULL;
920 }
921 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Loaded OS/2 dll %s using DosLoadModule.",
922 lpszLibFile, hFile, dwFlags, hDll, szModname));
923 return hDll; //happens when LoadLibrary is called in kernel32's initterm (nor harmful)
924 }
925 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Loaded %s using DosLoadModule.",
926 lpszLibFile, hFile, dwFlags, hDll, szModname));
927 return pModule->getInstanceHandle();
928 }
929 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): DosLoadModule (%s) failed. LastError=%d",
930 lpszLibFile, hFile, dwFlags, szModname, GetLastError()));
931 }
932 else
933 hDll = NULL;
934
935
936 /** @sketch
937 * If PE image THEN
938 * IF LOAD_LIBRARY_AS_DATAFILE or Executable THEN
939 *
940 *
941 * Try load the file using the Win32PeLdrDll class.
942 * <sketch continued further down>
943 * Else
944 * Set last error.
945 * (hDll is NULL)
946 * Endif
947 * return hDll.
948 */
949 if(fPE == ERROR_SUCCESS)
950 {
951 Win32PeLdrDll *peldrDll;
952
953 //SvL: If executable -> load as data file (only resources)
954 if(!(Characteristics & IMAGE_FILE_DLL))
955 {
956 dwFlags |= (LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES);
957 }
958
959 peldrDll = new Win32PeLdrDll(szModname);
960 if (peldrDll == NULL)
961 {
962 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Failed to created instance of Win32PeLdrDll. returns NULL.",
963 lpszLibFile, hFile, dwFlags));
964 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
965 return NULL;
966 }
967
968 /** @sketch
969 * Process dwFlags
970 */
971 if (dwFlags & LOAD_LIBRARY_AS_DATAFILE)
972 {
973 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): LOAD_LIBRARY_AS_DATAFILE",
974 lpszLibFile, hFile, dwFlags));
975 peldrDll->setLoadAsDataFile();
976 peldrDll->disableLibraryCalls();
977 }
978 if (dwFlags & DONT_RESOLVE_DLL_REFERENCES)
979 {
980 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): DONT_RESOLVE_DLL_REFERENCES",
981 lpszLibFile, hFile, dwFlags));
982 peldrDll->disableLibraryCalls();
983 peldrDll->disableImportHandling();
984 }
985 if (dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH)
986 {
987 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Warning dwFlags LOAD_WITH_ALTERED_SEARCH_PATH is not implemented.",
988 lpszLibFile, hFile, dwFlags));
989 //peldrDll->setLoadWithAlteredSearchPath();
990 }
991
992 /** @sketch
993 * Initiate the peldr DLL.
994 * IF successful init THEN
995 * Inc dynamic ref count.
996 * Inc ref count.
997 * Attach to process
998 * IF successful THEN
999 * hDLL <- instance handle.
1000 * ELSE
1001 * set last error
1002 * delete Win32PeLdrDll instance.
1003 * Endif
1004 * ELSE
1005 * set last error
1006 * delete Win32PeLdrDll instance.
1007 * Endif.
1008 */
1009 if (peldrDll->init(0))
1010 {
1011 peldrDll->AddRef();
1012 if (peldrDll->attachProcess())
1013 {
1014 hDll = peldrDll->getInstanceHandle();
1015 //Must be called *after* attachprocess, since attachprocess may also
1016 //trigger LoadLibrary calls
1017 //Those dlls must not be put in front of this dll in the dynamic
1018 //dll list; or else the unload order is wrong:
1019 //i.e. RPAP3260 loads PNRS3260 in DLL_PROCESS_ATTACH
1020 // this means that in ExitProcess, PNRS3260 needs to be removed
1021 // first since RPAP3260 depends on it
1022 peldrDll->incDynamicLib();
1023 }
1024 else
1025 {
1026 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): attachProcess call to Win32PeLdrDll instance failed. returns NULL.",
1027 lpszLibFile, hFile, dwFlags));
1028 SetLastError(ERROR_DLL_INIT_FAILED);
1029 delete peldrDll;
1030 return NULL;
1031 }
1032 }
1033 else
1034 {
1035 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Failed to init Win32PeLdrDll instance. error=%d returns NULL.",
1036 lpszLibFile, hFile, dwFlags, peldrDll->getError()));
1037 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
1038 delete peldrDll;
1039 return NULL;
1040 }
1041 }
1042 else
1043 {
1044 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x) library wasn't found (%s) or isn't loadable; err %x",
1045 lpszLibFile, hFile, dwFlags, szModname, fPE));
1046 SetLastError(fPE);
1047 return NULL;
1048 }
1049
1050 return hDll;
1051}
1052
1053
1054/**
1055 * LoadLibraryExW can be used to map a DLL module into the calling process's
1056 * addressspace. It returns a handle that can be used with GetProcAddress to
1057 * get addresses of exported entry points (functions and variables).
1058 *
1059 * LoadLibraryExW can also be used to map executable (.exe) modules into the
1060 * address to access resources in the module. However, LoadLibrary can't be
1061 * used to run an executable (.exe) module.
1062 *
1063 * @returns Handle to the library which was loaded.
1064 * @param lpszLibFile Pointer to Unicode string giving the name of
1065 * the executable image (either a Dll or an Exe) which is to
1066 * be loaded.
1067 *
1068 * If no extention is specified the default .DLL extention is
1069 * appended to the name. End the filename with an '.' if the
1070 * file does not have an extention (and don't want the .DLL
1071 * appended).
1072 *
1073 * If no path is specified, this API will use the Odin32
1074 * standard search strategy to find the file. This strategy
1075 * is described in the method Win32ImageBase::findDLL.
1076 * This may be alterned by the LOAD_WITH_ALTERED_SEARCH_PATH
1077 * flag, see below.
1078 *
1079 * This API likes to have backslashes (\), but will probably
1080 * accept forward slashes too. Win32 SDK docs says that it
1081 * should not contain forward slashes.
1082 *
1083 * Win32 SDK docs adds:
1084 * "The name specified is the file name of the module and
1085 * is not related to the name stored in the library module
1086 * itself, as specified by the LIBRARY keyword in the
1087 * module-definition (.def) file."
1088 *
1089 * @param hFile Reserved. Must be 0.
1090 *
1091 * @param dwFlags Flags which specifies the taken when loading the module.
1092 * The value 0 makes it identical to LoadLibraryA/W.
1093 *
1094 * Flags:
1095 *
1096 * DONT_RESOLVE_DLL_REFERENCES
1097 * (WinNT/2K feature): Don't load imported modules and
1098 * hence don't resolve imported symbols.
1099 * DllMain isn't called either. (Which is obvious since
1100 * it may use one of the importe symbols.)
1101 *
1102 * On the other hand, if this flag is NOT set, the system
1103 * load imported modules, resolves imported symbols, calls
1104 * DllMain for process and thread init and term (if wished
1105 * by the module).
1106 *
1107 * LOAD_LIBRARY_AS_DATAFILE
1108 * If this flag is set, the module is mapped into the
1109 * address space but is not prepared for execution. Though
1110 * it's preparted for resource API. Hence, you'll use this
1111 * flag when you want to load a DLL for extracting
1112 * messages or resources from it.
1113 *
1114 * The resulting handle can be used with any Odin32 API
1115 * which operates on resources.
1116 * (WinNt/2k supports all resource APIs while Win9x don't
1117 * support the specialized resource APIs: LoadBitmap,
1118 * LoadCursor, LoadIcon, LoadImage, LoadMenu.)
1119 *
1120 * LOAD_WITH_ALTERED_SEARCH_PATH
1121 * If this flag is set and lpszLibFile specifies a path
1122 * we'll use an alternative file search strategy to find
1123 * imported modules. This stratgy is simply to use the
1124 * path of the module being loaded instead of the path
1125 * of the executable module as the first location
1126 * to search for imported modules.
1127 *
1128 * If this flag is clear, the standard Odin32 standard
1129 * search strategy. See Win32ImageBase::findDll for
1130 * further information.
1131 *
1132 * @sketch Convert Unicode name to ascii.
1133 * Call LoadLibraryExA.
1134 * Free ascii string.
1135 * return handle from LoadLibraryExA.
1136 * @status Open32 Partially Implemented.
1137 * @author Sander van Leeuwen (sandervl@xs4all.nl)
1138 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
1139 * @remark Forwards to LoadLibraryExA.
1140 */
1141HINSTANCE WIN32API LoadLibraryExW(LPCWSTR lpszLibFile, HANDLE hFile, DWORD dwFlags)
1142{
1143 char * pszAsciiLibFile;
1144 HINSTANCE hDll;
1145
1146 pszAsciiLibFile = UnicodeToAsciiString(lpszLibFile);
1147 dprintf(("KERNEL32: LoadLibraryExW(%s, 0x%x, 0x%x) --> LoadLibraryExA",
1148 pszAsciiLibFile, hFile, dwFlags));
1149 hDll = LoadLibraryExA(pszAsciiLibFile, hFile, dwFlags);
1150 dprintf(("KERNEL32: LoadLibraryExW(%s, 0x%x, 0x%x) returns 0x%x",
1151 pszAsciiLibFile, hFile, dwFlags, hDll));
1152 FreeAsciiString(pszAsciiLibFile);
1153
1154 return hDll;
1155}
1156//******************************************************************************
1157//******************************************************************************
1158HINSTANCE16 WIN32API LoadLibrary16(LPCTSTR lpszLibFile)
1159{
1160 dprintf(("ERROR: LoadLibrary16 %s, not implemented", lpszLibFile));
1161 return 0;
1162}
1163//******************************************************************************
1164//******************************************************************************
1165VOID WIN32API FreeLibrary16(HINSTANCE16 hinstance)
1166{
1167 dprintf(("ERROR: FreeLibrary16 %x, not implemented", hinstance));
1168}
1169//******************************************************************************
1170//******************************************************************************
1171FARPROC WIN32API GetProcAddress16(HMODULE hModule, LPCSTR lpszProc)
1172{
1173 dprintf(("ERROR: GetProcAddress16 %x %x, not implemented", hModule, lpszProc));
1174 return 0;
1175}
1176
1177
1178/**
1179 * Internal function which gets the commandline (string) used to start the current process.
1180 * @returns OS/2 / Windows return code
1181 * On successful return (NO_ERROR) the global variables
1182 * pszCmdLineA and pszCmdLineW are set.
1183 *
1184 * @param pszPeExe Pass in the name of the PE exe of this process. We'll
1185 * us this as exename and skip the first argument (ie. argv[1]).
1186 * If NULL we'll use the commandline from OS/2 as it is.
1187 * @status Completely implemented and tested.
1188 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1189 */
1190ULONG InitCommandLine(const char *pszPeExe)
1191{
1192 PCHAR pib_pchcmd; /* PIB pointer to commandline. */
1193 CHAR szFilename[CCHMAXPATH]; /* Filename buffer used to get the exe filename in. */
1194 ULONG cch; /* Commandline string length. (including terminator) */
1195 PSZ psz; /* Temporary string pointer. */
1196 PSZ psz2; /* Temporary string pointer. */
1197 APIRET rc; /* OS/2 return code. */
1198 BOOL fQuotes; /* Flag used to remember if the exe filename should be in quotes. */
1199
1200 /** @sketch
1201 * Get commandline from the PIB.
1202 */
1203 pib_pchcmd = (PCHAR)OSLibGetPIB(PIB_PCHCMD);
1204
1205 /** @sketch
1206 * Two methods of making the commandline:
1207 * (1) The first argument is skipped and the second is used as exe filname.
1208 * This applies to PE.EXE launched processes only.
1209 * (2) No skipping. First argument is the exe filename.
1210 * This applies to all but PE.EXE launched processes.
1211 *
1212 * Note: We could do some code size optimization here. Much of the code for
1213 * the two methods are nearly identical.
1214 *
1215 */
1216 if(pszPeExe)
1217 {
1218 /** @sketch
1219 * Allocate memory for the commandline.
1220 * Build commandline:
1221 * Copy exe filename.
1222 * Add arguments.
1223 */
1224 cch = strlen(pszPeExe)+1;
1225
1226 // PH 2002-04-11
1227 // Note: intentional memory leak, pszCmdLineW will not be freed
1228 // or allocated after process startup
1229 pszCmdLineA = psz = (PSZ)malloc(cch);
1230 if (psz == NULL)
1231 {
1232 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed\n", pszPeExe, cch));
1233 return ERROR_NOT_ENOUGH_MEMORY;
1234 }
1235 strcpy((char *)pszCmdLineA, pszPeExe);
1236
1237 rc = NO_ERROR;
1238 }
1239 else
1240 {
1241 /** @sketch Method (2):
1242 * First we'll have to determin the size of the commandline.
1243 *
1244 * As we don't assume that OS/2 allways puts a fully qualified EXE name
1245 * as the first string, we'll check if it's empty - and get the modulename
1246 * in that case - and allways get the fully qualified filename.
1247 */
1248 if (pib_pchcmd == NULL || pib_pchcmd[0] == '\0')
1249 {
1250 rc = OSLibDosQueryModuleName(OSLibGetPIB(PIB_HMTE), sizeof(szFilename), szFilename);
1251 if (rc != NO_ERROR)
1252 {
1253 dprintf(("KERNEL32: InitCommandLine(%p): OSLibQueryModuleName(0x%x,...) failed with rc=%d\n",
1254 pszPeExe, OSLibGetPIB(PIB_HMTE), rc));
1255 return rc;
1256 }
1257 }
1258 else
1259 {
1260 rc = OSLibDosQueryPathInfo(pib_pchcmd, FIL_QUERYFULLNAME, szFilename, sizeof(szFilename));
1261 if (rc != NO_ERROR)
1262 {
1263 dprintf(("KERNEL32: InitCommandLine(%p): (info) OSLibDosQueryPathInfo failed with rc=%d\n", pszPeExe, rc));
1264 strcpy(szFilename, pib_pchcmd);
1265 rc = NO_ERROR;
1266 }
1267 }
1268
1269 /** @sketch
1270 * We're still measuring the size of the commandline:
1271 * Check if we have to quote the exe filename.
1272 * Determin the length of the executable name including quotes and '\0'-terminator.
1273 * Count the length of the arguments. (We here count's all argument strings.)
1274 */
1275 fQuotes = strchr(szFilename, ' ') != NULL;
1276 cch = strlen(szFilename) + fQuotes*2 + 1;
1277 if (pib_pchcmd != NULL)
1278 {
1279 psz2 = pib_pchcmd + strlen(pib_pchcmd) + 1;
1280 while (*psz2 != '\0')
1281 {
1282 register int cchTmp = strlen(psz2) + 1; /* + 1 is for terminator (psz2) and space (cch). */
1283 psz2 += cchTmp;
1284 cch += cchTmp;
1285 }
1286 }
1287
1288 /** @sketch
1289 * Allocate memory for the commandline.
1290 * Build commandline:
1291 * Copy exe filename.
1292 * Add arguments.
1293 */
1294 pszCmdLineA = psz = (PSZ)malloc(cch);
1295 if (psz == NULL)
1296 {
1297 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed\n", pszPeExe, cch));
1298 return ERROR_NOT_ENOUGH_MEMORY;
1299 }
1300
1301 if (fQuotes)
1302 *psz++ = '"';
1303 strcpy(psz, szFilename);
1304 psz += strlen(psz);
1305 if (fQuotes)
1306 {
1307 *psz++ = '"';
1308 *psz = '\0';
1309 }
1310
1311 if (pib_pchcmd != NULL)
1312 {
1313 psz2 = pib_pchcmd + strlen(pib_pchcmd) + 1;
1314 while (*psz2 != '\0')
1315 {
1316 register int cchTmp = strlen(psz2) + 1; /* + 1 is for terminator (psz). */
1317 *psz++ = ' '; /* add space */
1318 memcpy(psz, psz2, cchTmp);
1319 psz2 += cchTmp;
1320 psz += cchTmp - 1;
1321 }
1322 }
1323 }
1324
1325 /** @sketch
1326 * If successfully build ASCII commandline then convert it to UniCode.
1327 */
1328 if (rc == NO_ERROR)
1329 {
1330 // PH 2002-04-11
1331 // Note: intentional memory leak, pszCmdLineW will not be freed
1332 // or allocated after process startup
1333 pszCmdLineW = (WCHAR*)malloc(cch * 2);
1334 if (pszCmdLineW != NULL)
1335 AsciiToUnicode(pszCmdLineA, (WCHAR*)pszCmdLineW);
1336 else
1337 {
1338 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed (2)\n", pszPeExe, cch));
1339 rc = ERROR_NOT_ENOUGH_MEMORY;
1340 }
1341 }
1342
1343 return rc;
1344}
1345
1346/**
1347 * Gets the command line of the current process.
1348 * @returns On success:
1349 * Command line of the current process. One single string.
1350 * The first part of the command line string is the executable filename
1351 * of the current process. It might be in quotes if it contains spaces.
1352 * The rest of the string is arguments.
1353 *
1354 * On error:
1355 * NULL. Last error set. (does Win32 set last error this?)
1356 * @sketch IF not inited THEN
1357 * Init commandline assuming !PE.EXE
1358 * IF init failes THEN set last error.
1359 * ENDIF
1360 * return ASCII/ANSI commandline.
1361 * @status Completely implemented and tested.
1362 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1363 * @remark The Ring-3 PeLdr is resposible for calling InitCommandLine before anyone
1364 * is able to call this function.
1365 */
1366LPCSTR WIN32API GetCommandLineA(VOID)
1367{
1368 /*
1369 * Check if the commandline is initiated.
1370 * If not we'll have to do it.
1371 * ASSUMES that if not inited this isn't a PE.EXE lauched process.
1372 */
1373 if (pszCmdLineA == NULL)
1374 {
1375 APIRET rc;
1376 rc = InitCommandLine(NULL);
1377 if (rc != NULL)
1378 SetLastError(rc);
1379 }
1380
1381 dprintf(("KERNEL32: GetCommandLineA: %s\n", pszCmdLineA));
1382 return pszCmdLineA;
1383}
1384
1385
1386/**
1387 * Gets the command line of the current process.
1388 * @returns On success:
1389 * Command line of the current process. One single string.
1390 * The first part of the command line string is the executable filename
1391 * of the current process. It might be in quotes if it contains spaces.
1392 * The rest of the string is arguments.
1393 *
1394 * On error:
1395 * NULL. Last error set. (does Win32 set last error this?)
1396 * @sketch IF not inited THEN
1397 * Init commandline assuming !PE.EXE
1398 * IF init failes THEN set last error.
1399 * ENDIF
1400 * return Unicode commandline.
1401 * @status Completely implemented and tested.
1402 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1403 * @remark The Ring-3 PeLdr is resposible for calling InitCommandLine before anyone
1404 * is able to call this function.
1405 */
1406LPCWSTR WIN32API GetCommandLineW(void)
1407{
1408 /*
1409 * Check if the commandline is initiated.
1410 * If not we'll have to do it.
1411 * ASSUMES that if not inited this isn't a PE.EXE lauched process.
1412 */
1413 if (pszCmdLineW == NULL)
1414 {
1415 APIRET rc;
1416 rc = InitCommandLine(NULL);
1417 if (rc != NULL)
1418 SetLastError(rc);
1419 }
1420
1421 dprintf(("KERNEL32: GetCommandLineW: %s\n", pszCmdLineA));
1422 return pszCmdLineW;
1423}
1424
1425
1426/**
1427 * GetModuleFileName gets the full path and file name for the specified module.
1428 * @returns Bytes written to the buffer (lpszPath). This count includes the
1429 * terminating '\0'.
1430 * On error 0 is returned. Last error is set.
1431 *
1432 * 2002-04-25 PH
1433 * Q - Do we set ERROR_BUFFER_OVERFLOW when cch > cchPath?
1434 * Q - Does NT really set the last error?
1435 * A > Win2k does not set LastError here, remains OK
1436 *
1437 * While GetModuleFileName does add a trailing termination zero
1438 * if there is enough room, the returned number of characters
1439 * *MUST NOT* include the zero character!
1440 * (Notes R6 Installer on Win2kSP6, verified Testcase)
1441 *
1442 * @param hModule Handle to the module you like to get the file name to.
1443 * @param lpszPath Output buffer for full path and file name.
1444 * @param cchPath Size of the lpszPath buffer.
1445 * @sketch Validate lpszPath.
1446 * Find the module object using handle.
1447 * If found Then
1448 * Get full path from module object.
1449 * If found path Then
1450 * Copy path to buffer and set the number of bytes written.
1451 * Else
1452 * IPE!
1453 * Else
1454 * Call Open32 GetModuleFileName. (kernel32 initterm needs/needed this)
1455 * Log result.
1456 * Return number of bytes written to the buffer.
1457 *
1458 * @status Completely implemented, Open32.
1459 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1460 * Sander van Leeuwen (sandervl@xs4all.nl)
1461 * Patrick Haller (patrick.haller@innotek.de)
1462 * @remark - Do we still have to call Open32?
1463 */
1464DWORD WIN32API GetModuleFileNameA(HMODULE hModule, LPTSTR lpszPath, DWORD cchPath)
1465{
1466 Win32ImageBase * pMod; /* Pointer to the module object. */
1467 DWORD cch = 0; /* Length of the */
1468
1469 // PH 2002-04-24 Note:
1470 // WIN2k just crashes in NTDLL if lpszPath is invalid!
1471 if (!VALID_PSZ(lpszPath))
1472 {
1473 dprintf(("KERNEL32: GetModuleFileNameA(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
1474 hModule, lpszPath, cchPath, lpszPath));
1475 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
1476 return 0;
1477 }
1478
1479 pMod = Win32ImageBase::findModule(hModule);
1480 if (pMod != NULL)
1481 {
1482 const char *pszFn = pMod->getFullPath();
1483 if (pszFn)
1484 {
1485 cch = strlen(pszFn);
1486 if (cch >= cchPath)
1487 cch = cchPath;
1488 else
1489 // if there is sufficient room for the zero termination,
1490 // write it additionally, uncounted
1491 lpszPath[cch] = '\0';
1492
1493 memcpy(lpszPath, pszFn, cch);
1494 }
1495 else
1496 {
1497 dprintf(("KERNEL32: GetModuleFileNameA(%x,...): IPE - getFullPath returned NULL or empty string\n"));
1498 DebugInt3();
1499 SetLastError(ERROR_INVALID_HANDLE);
1500 }
1501 }
1502 else
1503 {
1504 SetLastError(ERROR_INVALID_HANDLE);
1505 //only needed for call inside kernel32's initterm (profile init)
1506 //(console init only it seems...)
1507 cch = OSLibDosGetModuleFileName(hModule, lpszPath, cchPath);
1508 }
1509
1510 if (cch > 0)
1511 dprintf(("KERNEL32: GetModuleFileNameA(%x %x): %s %d\n", hModule, lpszPath, lpszPath, cch));
1512 else
1513 dprintf(("KERNEL32: WARNING: GetModuleFileNameA(%x,...) - not found!", hModule));
1514
1515 return cch;
1516}
1517
1518
1519/**
1520 * GetModuleFileName gets the full path and file name for the specified module.
1521 * @returns Bytes written to the buffer (lpszPath). This count includes the
1522 * terminating '\0'.
1523 * On error 0 is returned. Last error is set.
1524 * @param hModule Handle to the module you like to get the file name to.
1525 * @param lpszPath Output buffer for full path and file name.
1526 * @param cchPath Size of the lpszPath buffer.
1527 * @sketch Find the module object using handle.
1528 * If found Then
1529 * get full path from module object.
1530 * If found path Then
1531 * Determin path length.
1532 * Translate the path to into the buffer.
1533 * Else
1534 * IPE.
1535 * else
1536 * SetLastError to invalid handle.
1537 * Log result.
1538 * return number of bytes written to the buffer.
1539 *
1540 * @status Completely implemented.
1541 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1542 * @remark - We do _NOT_ call Open32.
1543 * - Do we set ERROR_BUFFER_OVERFLOW when cch > cchPath?
1544 * - Does NT really set the last error?
1545 */
1546DWORD WIN32API GetModuleFileNameW(HMODULE hModule, LPWSTR lpszPath, DWORD cchPath)
1547{
1548 Win32ImageBase * pMod;
1549 DWORD cch = 0;
1550
1551 if (!VALID_PSZ(lpszPath))
1552 {
1553 dprintf(("KERNEL32: GetModuleFileNameW(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
1554 hModule, lpszPath, cchPath, lpszPath));
1555 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
1556 return 0;
1557 }
1558
1559 pMod = Win32ImageBase::findModule(hModule);
1560 if (pMod != NULL)
1561 {
1562 const char *pszFn = pMod->getFullPath();
1563 if (pszFn || *pszFn != '\0')
1564 {
1565 cch = strlen(pszFn) + 1;
1566 if (cch > cchPath)
1567 cch = cchPath;
1568 AsciiToUnicodeN(pszFn, lpszPath, cch);
1569 }
1570 else
1571 {
1572 dprintf(("KERNEL32: GetModuleFileNameW(%x,...): IPE - getFullPath returned NULL or empty string\n"));
1573 DebugInt3();
1574 SetLastError(ERROR_INVALID_HANDLE);
1575 }
1576 }
1577 else
1578 SetLastError(ERROR_INVALID_HANDLE);
1579
1580 if (cch > 0)
1581 dprintf(("KERNEL32: GetModuleFileNameW(%x,...): %s %d\n", hModule, lpszPath, cch));
1582 else
1583 dprintf(("KERNEL32: WARNING: GetModuleFileNameW(%x,...) - not found!", hModule));
1584
1585 return cch;
1586}
1587
1588
1589//******************************************************************************
1590//NOTE: GetModuleHandleA does NOT support files with multiple dots (i.e.
1591// very.weird.exe)
1592//
1593// hinst = LoadLibrary("WINSPOOL.DRV"); -> succeeds
1594// hinst2 = GetModuleHandle("WINSPOOL.DRV"); -> succeeds
1595// hinst3 = GetModuleHandle("WINSPOOL."); -> fails
1596// hinst4 = GetModuleHandle("WINSPOOL"); -> fails
1597// hinst = LoadLibrary("KERNEL32.DLL"); -> succeeds
1598// hinst2 = GetModuleHandle("KERNEL32.DLL"); -> succeeds
1599// hinst3 = GetModuleHandle("KERNEL32."); -> fails
1600// hinst4 = GetModuleHandle("KERNEL32"); -> succeeds
1601// Same behaviour as observed in NT4, SP6
1602//******************************************************************************
1603HANDLE WIN32API GetModuleHandleA(LPCTSTR lpszModule)
1604{
1605 HANDLE hMod = 0;
1606 Win32DllBase *windll;
1607 char szModule[CCHMAXPATH];
1608 char *dot;
1609
1610 if(lpszModule == NULL)
1611 {
1612 if(WinExe)
1613 hMod = WinExe->getInstanceHandle();
1614 else
1615 {
1616 // // Just fail this API
1617 // hMod = 0;
1618 // SetLastError(ERROR_INVALID_HANDLE);
1619 // Wrong: in an ODIN32-LX environment, just
1620 // assume a fake handle
1621 hMod = -1;
1622 }
1623 }
1624 else
1625 {
1626 strcpy(szModule, OSLibStripPath((char *)lpszModule));
1627 strupr(szModule);
1628 dot = strchr(szModule, '.');
1629 if(dot == NULL) {
1630 //if no extension -> add .DLL (see SDK docs)
1631 strcat(szModule, DLL_EXTENSION);
1632 }
1633 else {
1634 if(dot[1] == 0) {
1635 //a trailing dot means the module has no extension (SDK docs)
1636 *dot = 0;
1637 }
1638 }
1639 if(WinExe && WinExe->matchModName(szModule)) {
1640 hMod = WinExe->getInstanceHandle();
1641 }
1642 else {
1643 windll = Win32DllBase::findModule(szModule);
1644 if(windll) {
1645 hMod = windll->getInstanceHandle();
1646 }
1647 }
1648 }
1649 dprintf(("KERNEL32: GetModuleHandle %s returned %X\n", lpszModule, hMod));
1650 return(hMod);
1651}
1652//******************************************************************************
1653//******************************************************************************
1654HMODULE WIN32API GetModuleHandleW(LPCWSTR lpwszModuleName)
1655{
1656 HMODULE rc;
1657 char *astring = NULL;
1658
1659 if (NULL != lpwszModuleName)
1660 astring = UnicodeToAsciiString((LPWSTR)lpwszModuleName);
1661
1662 rc = GetModuleHandleA(astring);
1663 dprintf(("KERNEL32: OS2GetModuleHandleW %s returned %X\n", astring, rc));
1664
1665 if (NULL != astring)
1666 FreeAsciiString(astring);
1667
1668 return(rc);
1669}
1670//******************************************************************************
1671//******************************************************************************
1672BOOL WINAPI CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine,
1673 LPSECURITY_ATTRIBUTES lpProcessAttributes,
1674 LPSECURITY_ATTRIBUTES lpThreadAttributes,
1675 BOOL bInheritHandles, DWORD dwCreationFlags,
1676 LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
1677 LPSTARTUPINFOA lpStartupInfo,
1678 LPPROCESS_INFORMATION lpProcessInfo )
1679{
1680 TEB *pThreadDB = (TEB*)GetThreadTEB();
1681 char *cmdline = NULL;
1682 BOOL rc;
1683
1684 dprintf(("KERNEL32: CreateProcessA %s cline:%s inherit:%d cFlags:%x Env:%x CurDir:%s StartupFlags:%x\n",
1685 lpApplicationName, lpCommandLine, bInheritHandles, dwCreationFlags,
1686 lpEnvironment, lpCurrentDirectory, lpStartupInfo));
1687
1688#ifdef DEBUG
1689 if(lpStartupInfo) {
1690 dprintf(("lpStartupInfo->lpReserved %x", lpStartupInfo->lpReserved));
1691 dprintf(("lpStartupInfo->lpDesktop %x", lpStartupInfo->lpDesktop));
1692 dprintf(("lpStartupInfo->lpTitle %s", lpStartupInfo->lpTitle));
1693 dprintf(("lpStartupInfo->dwX %x", lpStartupInfo->dwX));
1694 dprintf(("lpStartupInfo->dwY %x", lpStartupInfo->dwY));
1695 dprintf(("lpStartupInfo->dwXSize %x", lpStartupInfo->dwXSize));
1696 dprintf(("lpStartupInfo->dwYSize %x", lpStartupInfo->dwYSize));
1697 dprintf(("lpStartupInfo->dwXCountChars %x", lpStartupInfo->dwXCountChars));
1698 dprintf(("lpStartupInfo->dwYCountChars %x", lpStartupInfo->dwYCountChars));
1699 dprintf(("lpStartupInfo->dwFillAttribute %x", lpStartupInfo->dwFillAttribute));
1700 dprintf(("lpStartupInfo->dwFlags %x", lpStartupInfo->dwFlags));
1701 dprintf(("lpStartupInfo->wShowWindow %x", lpStartupInfo->wShowWindow));
1702 dprintf(("lpStartupInfo->hStdInput %x", lpStartupInfo->hStdInput));
1703 dprintf(("lpStartupInfo->hStdOutput %x", lpStartupInfo->hStdOutput));
1704 dprintf(("lpStartupInfo->hStdError %x", lpStartupInfo->hStdError));
1705 }
1706#endif
1707
1708 // open32 does not support DEBUG_ONLY_THIS_PROCESS
1709 if(dwCreationFlags & DEBUG_ONLY_THIS_PROCESS)
1710 dwCreationFlags |= DEBUG_PROCESS;
1711
1712 if(O32_CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes,
1713 lpThreadAttributes, bInheritHandles, dwCreationFlags,
1714 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
1715 lpProcessInfo) == TRUE)
1716 {
1717 if (dwCreationFlags & DEBUG_PROCESS && pThreadDB != NULL)
1718 {
1719 if(pThreadDB->o.odin.pidDebuggee != 0)
1720 {
1721 // TODO: handle this
1722 dprintf(("KERNEL32: CreateProcess ERROR: This thread is already a debugger\n"));
1723 }
1724 else
1725 {
1726 pThreadDB->o.odin.pidDebuggee = lpProcessInfo->dwProcessId;
1727 OSLibStartDebugger((ULONG*)&pThreadDB->o.odin.pidDebuggee);
1728 }
1729 }
1730 else pThreadDB->o.odin.pidDebuggee = 0;
1731
1732 return(TRUE);
1733 }
1734
1735 // PH 2001-05-07
1736 // verify why O32_CreateProcess actually failed.
1737 // If GetLastError() == 191 (ERROR_INVALID_EXE_SIGNATURE)
1738 // we can continue to call "PE.EXE".
1739 // Note: Open32 does not translate ERROR_INVALID_EXE_SIGNATURE,
1740 // it is also valid in Win32.
1741 DWORD dwError = GetLastError();
1742 if (ERROR_INVALID_EXE_SIGNATURE != dwError && ERROR_FILE_NOT_FOUND != dwError && ERROR_ACCESS_DENIED != dwError)
1743 {
1744 dprintf(("CreateProcess: O32_CreateProcess failed with rc=%d, not PE-executable !",
1745 dwError));
1746
1747 // the current value of GetLastError() is still valid.
1748
1749 return FALSE;
1750 }
1751
1752 // else ...
1753
1754 //probably a win32 exe, so run it in the pe loader
1755 if(lpApplicationName) {
1756 if(lpCommandLine) {
1757 //skip exe name in lpCommandLine
1758 //TODO: doesn't work for directories with spaces!
1759 while(*lpCommandLine != 0 && *lpCommandLine != ' ')
1760 lpCommandLine++;
1761
1762 if(*lpCommandLine != 0) {
1763 lpCommandLine++;
1764 }
1765 cmdline = (char *)malloc(strlen(lpApplicationName)+strlen(lpCommandLine) + 16);
1766 sprintf(cmdline, "%s %s", lpApplicationName, lpCommandLine);
1767 }
1768 else {
1769 cmdline = (char *)malloc(strlen(lpApplicationName) + 16);
1770 sprintf(cmdline, "%s", lpApplicationName);
1771 }
1772 }
1773 else {
1774 cmdline = (char *)malloc(strlen(lpCommandLine) + 16);
1775 sprintf(cmdline, "%s", lpCommandLine);
1776 }
1777
1778 char szAppName[MAX_PATH];
1779 char buffer[MAX_PATH];
1780 DWORD fileAttr;
1781 char *exename = buffer;
1782 strncpy(buffer, cmdline, sizeof(szAppName));
1783 buffer[MAX_PATH-1] = 0;
1784 if(*exename == '"') {
1785 exename++;
1786 while(*exename != 0 && *exename != '"')
1787 exename++;
1788
1789 if(*exename != 0) {
1790 *exename = 0;
1791 }
1792 exename++;
1793 if (SearchPathA( NULL, &buffer[1], ".exe", sizeof(szAppName), szAppName, NULL ) ||
1794 SearchPathA( NULL, &buffer[1], NULL, sizeof(szAppName), szAppName, NULL ))
1795 {
1796 //
1797 }
1798 }
1799 else {
1800 BOOL fTerminate = FALSE;
1801 DWORD fileAttr;
1802
1803 while(*exename != 0) {
1804 while(*exename != 0 && *exename != ' ')
1805 exename++;
1806
1807 if(*exename != 0) {
1808 *exename = 0;
1809 fTerminate = TRUE;
1810 }
1811 dprintf(("Trying '%s'", buffer ));
1812 if (SearchPathA( NULL, buffer, ".exe", sizeof(szAppName), szAppName, NULL ) ||
1813 SearchPathA( NULL, buffer, NULL, sizeof(szAppName), szAppName, NULL ))
1814 {
1815 if(fTerminate) exename++;
1816 break;
1817 }
1818
1819 if(fTerminate) {
1820 *exename = ' ';
1821 exename++;
1822 fTerminate = FALSE;
1823 }
1824 }
1825 }
1826 lpCommandLine = exename; //start of command line parameters
1827
1828 fileAttr = GetFileAttributesA(szAppName);
1829 if(fileAttr == -1 || (fileAttr & FILE_ATTRIBUTE_DIRECTORY)) {
1830 dprintf(("CreateProcess: can't find executable!"));
1831 SetLastError(ERROR_FILE_NOT_FOUND);
1832 return FALSE;
1833 }
1834
1835 dprintf(("KERNEL32: CreateProcess %s %s", szAppName, lpCommandLine));
1836
1837 DWORD Characteristics, SubSystem, fNEExe;
1838 if(Win32ImageBase::isPEImage(szAppName, &Characteristics, &SubSystem, &fNEExe) == 0)
1839 {
1840 char *lpszPE;
1841 char *lpszExecutable;
1842 int iNewCommandLineLength;
1843
1844 // calculate base length for the new command line
1845 iNewCommandLineLength = strlen(szAppName) + strlen(lpCommandLine);
1846
1847 if(SubSystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
1848 lpszExecutable = "PEC.EXE";
1849 else
1850 lpszExecutable = "PE.EXE";
1851
1852 lpszPE = lpszExecutable;
1853
1854 // 2002-04-24 PH
1855 // set the ODIN32.DEBUG_CHILD environment variable to start new PE processes
1856 // under a new instance of the (IPMD) debugger.
1857#ifdef DEBUG
1858 CHAR debug_szPE[ 512 ];
1859 PSZ debug_pszOS2Debugger = getenv("ODIN32.DEBUG_CHILD");
1860 if (NULL != debug_pszOS2Debugger)
1861 {
1862 // build new start command
1863 strcpy(debug_szPE, debug_pszOS2Debugger);
1864 strcat(debug_szPE, " ");
1865 strcat(debug_szPE, lpszExecutable);
1866
1867 // we require more space in the new command line
1868 iNewCommandLineLength += strlen( debug_szPE );
1869
1870 // only launch the specified executable (ICSDEBUG.EXE)
1871 lpszPE = debug_szPE;
1872 lpszExecutable = debug_pszOS2Debugger;
1873 }
1874#endif
1875
1876 //SvL: Allright. Before we call O32_CreateProcess, we must take care of
1877 // lpCurrentDirectory ourselves. (Open32 ignores it!)
1878 if(lpCurrentDirectory) {
1879 char *newcmdline;
1880
1881 newcmdline = (char *)malloc(strlen(lpCurrentDirectory) + iNewCommandLineLength + 32);
1882 sprintf(newcmdline, "%s /OPT:[CURDIR=%s] %s %s", lpszPE, lpCurrentDirectory, szAppName, lpCommandLine);
1883 free(cmdline);
1884 cmdline = newcmdline;
1885 }
1886 else {
1887 char *newcmdline;
1888
1889 newcmdline = (char *)malloc(iNewCommandLineLength + 16);
1890 sprintf(newcmdline, "%s %s %s", lpszPE, szAppName, lpCommandLine);
1891 free(cmdline);
1892 cmdline = newcmdline;
1893 }
1894
1895 dprintf(("KERNEL32: CreateProcess starting [%s],[%s]",
1896 lpszExecutable,
1897 cmdline));
1898
1899 rc = O32_CreateProcess(lpszExecutable, (LPCSTR)cmdline,lpProcessAttributes,
1900 lpThreadAttributes, bInheritHandles, dwCreationFlags,
1901 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
1902 lpProcessInfo);
1903 }
1904 else
1905 if(fNEExe) {//16 bits windows app
1906 char *newcmdline;
1907
1908 newcmdline = (char *)malloc(strlen(szAppName) + strlen(cmdline) + 16);
1909 sprintf(newcmdline, "w16odin.exe %s", szAppName, lpCommandLine);
1910 free(cmdline);
1911 cmdline = newcmdline;
1912 //Force Open32 to use DosStartSession (DosExecPgm won't do)
1913 dwCreationFlags |= CREATE_NEW_PROCESS_GROUP;
1914 rc = O32_CreateProcess("w16odin.exe", (LPCSTR)cmdline, lpProcessAttributes,
1915 lpThreadAttributes, bInheritHandles, dwCreationFlags,
1916 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
1917 lpProcessInfo);
1918 }
1919 else {//os/2 app??
1920 rc = O32_CreateProcess(szAppName, (LPCSTR)lpCommandLine, lpProcessAttributes,
1921 lpThreadAttributes, bInheritHandles, dwCreationFlags,
1922 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
1923 lpProcessInfo);
1924 }
1925 if(rc == TRUE)
1926 {
1927 if (dwCreationFlags & DEBUG_PROCESS && pThreadDB != NULL)
1928 {
1929 if(pThreadDB->o.odin.pidDebuggee != 0)
1930 {
1931 // TODO: handle this
1932 dprintf(("KERNEL32: CreateProcess ERROR: This thread is already a debugger\n"));
1933 }
1934 else
1935 {
1936 pThreadDB->o.odin.pidDebuggee = lpProcessInfo->dwProcessId;
1937 OSLibStartDebugger((ULONG*)&pThreadDB->o.odin.pidDebuggee);
1938 }
1939 }
1940 else
1941 pThreadDB->o.odin.pidDebuggee = 0;
1942 }
1943 if(cmdline)
1944 free(cmdline);
1945
1946 if(lpProcessInfo)
1947 {
1948 lpProcessInfo->dwThreadId = MAKE_THREADID(lpProcessInfo->dwProcessId, lpProcessInfo->dwThreadId);
1949 dprintf(("KERNEL32: CreateProcess returned %d hPro:%x hThr:%x pid:%x tid:%x\n",
1950 rc, lpProcessInfo->hProcess, lpProcessInfo->hThread,
1951 lpProcessInfo->dwProcessId,lpProcessInfo->dwThreadId));
1952 }
1953 else
1954 dprintf(("KERNEL32: CreateProcess returned %d\n", rc));
1955 return(rc);
1956}
1957//******************************************************************************
1958//******************************************************************************
1959BOOL WIN32API CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
1960 PSECURITY_ATTRIBUTES lpProcessAttributes,
1961 PSECURITY_ATTRIBUTES lpThreadAttributes,
1962 BOOL bInheritHandles, DWORD dwCreationFlags,
1963 LPVOID lpEnvironment,
1964 LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
1965 LPPROCESS_INFORMATION lpProcessInfo)
1966{
1967 BOOL rc;
1968 char *astring1 = 0, *astring2 = 0, *astring3 = 0;
1969
1970 dprintf(("KERNEL32: CreateProcessW"));
1971 if(lpApplicationName)
1972 astring1 = UnicodeToAsciiString((LPWSTR)lpApplicationName);
1973 if(lpCommandLine)
1974 astring2 = UnicodeToAsciiString(lpCommandLine);
1975 if(lpCurrentDirectory)
1976 astring3 = UnicodeToAsciiString((LPWSTR)lpCurrentDirectory);
1977 rc = CreateProcessA(astring1, astring2, lpProcessAttributes, lpThreadAttributes,
1978 bInheritHandles, dwCreationFlags, lpEnvironment,
1979 astring3, (LPSTARTUPINFOA)lpStartupInfo,
1980 lpProcessInfo);
1981 if(astring3) FreeAsciiString(astring3);
1982 if(astring2) FreeAsciiString(astring2);
1983 if(astring1) FreeAsciiString(astring1);
1984 return(rc);
1985}
1986//******************************************************************************
1987//******************************************************************************
1988HINSTANCE WIN32API WinExec(LPCSTR lpCmdLine, UINT nCmdShow)
1989{
1990 STARTUPINFOA startinfo = {0};
1991 PROCESS_INFORMATION procinfo;
1992 DWORD rc;
1993 HINSTANCE hInstance;
1994
1995 dprintf(("KERNEL32: WinExec %s\n", lpCmdLine));
1996 startinfo.dwFlags = nCmdShow;
1997 if(CreateProcessA(NULL, (LPSTR)lpCmdLine, NULL, NULL, FALSE, 0, NULL, NULL,
1998 &startinfo, &procinfo) == FALSE)
1999 {
2000 hInstance = (HINSTANCE)GetLastError();
2001 if(hInstance >= 32) {
2002 hInstance = 11;
2003 }
2004 dprintf(("KERNEL32: WinExec failed with rc %d", hInstance));
2005 return hInstance;
2006 }
2007 //block until the launched app waits for input (or a timeout of 15 seconds)
2008 //TODO: Shouldn't call Open32, but the api in user32..
2009 if(fVersionWarp3) {
2010 Sleep(1000); //WaitForInputIdle not available in Warp 3
2011 }
2012 else {
2013 dprintf(("Calling WaitForInputIdle %x %d", procinfo.hProcess, 15000));
2014 rc = WaitForInputIdle(procinfo.hProcess, 15000);
2015#ifdef DEBUG
2016 if(rc != 0) {
2017 dprintf(("WinExec: WaitForInputIdle %x returned %x", procinfo.hProcess, rc));
2018 }
2019 else dprintf(("WinExec: WaitForInputIdle successfull"));
2020#endif
2021 }
2022 CloseHandle(procinfo.hThread);
2023 CloseHandle(procinfo.hProcess);
2024 return 33;
2025}
2026//******************************************************************************
2027//DWORD idAttach; /* thread to attach */
2028//DWORD idAttachTo; /* thread to attach to */
2029//BOOL fAttach; /* attach or detach */
2030//******************************************************************************
2031BOOL WIN32API AttachThreadInput(DWORD idAttach, DWORD idAttachTo, BOOL fAttach)
2032{
2033 dprintf(("USER32: AttachThreadInput, not implemented\n"));
2034 return(TRUE);
2035}
2036//******************************************************************************
2037//******************************************************************************
2038DWORD WIN32API WaitForInputIdle(HANDLE hProcess, DWORD dwTimeOut)
2039{
2040 dprintf(("USER32: WaitForInputIdle %x %d\n", hProcess, dwTimeOut));
2041
2042 if(fVersionWarp3) {
2043 Sleep(1000);
2044 return 0;
2045 }
2046 else return O32_WaitForInputIdle(hProcess, dwTimeOut);
2047}
2048/**********************************************************************
2049 * LoadModule (KERNEL32.499)
2050 *
2051 * Wine: 20000909
2052 *
2053 * Copyright 1995 Alexandre Julliard
2054 */
2055HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock )
2056{
2057 LOADPARAMS *params = (LOADPARAMS *)paramBlock;
2058 PROCESS_INFORMATION info;
2059 STARTUPINFOA startup;
2060 HINSTANCE hInstance;
2061 LPSTR cmdline, p;
2062 char filename[MAX_PATH];
2063 BYTE len;
2064
2065 dprintf(("LoadModule %s %x", name, paramBlock));
2066
2067 if (!name) return ERROR_FILE_NOT_FOUND;
2068
2069 if (!SearchPathA( NULL, name, ".exe", sizeof(filename), filename, NULL ) &&
2070 !SearchPathA( NULL, name, NULL, sizeof(filename), filename, NULL ))
2071 return GetLastError();
2072
2073 len = (BYTE)params->lpCmdLine[0];
2074 if (!(cmdline = (LPSTR)HeapAlloc( GetProcessHeap(), 0, strlen(filename) + len + 2 )))
2075 return ERROR_NOT_ENOUGH_MEMORY;
2076
2077 strcpy( cmdline, filename );
2078 p = cmdline + strlen(cmdline);
2079 *p++ = ' ';
2080 memcpy( p, params->lpCmdLine + 1, len );
2081 p[len] = 0;
2082
2083 memset( &startup, 0, sizeof(startup) );
2084 startup.cb = sizeof(startup);
2085 if (params->lpCmdShow)
2086 {
2087 startup.dwFlags = STARTF_USESHOWWINDOW;
2088 startup.wShowWindow = params->lpCmdShow[1];
2089 }
2090
2091 if (CreateProcessA( filename, cmdline, NULL, NULL, FALSE, 0,
2092 params->lpEnvAddress, NULL, &startup, &info ))
2093 {
2094 /* Give 15 seconds to the app to come up */
2095 if ( WaitForInputIdle ( info.hProcess, 15000 ) == 0xFFFFFFFF )
2096 dprintf(("ERROR: WaitForInputIdle failed: Error %ld\n", GetLastError() ));
2097 hInstance = 33;
2098 /* Close off the handles */
2099 CloseHandle( info.hThread );
2100 CloseHandle( info.hProcess );
2101 }
2102 else if ((hInstance = GetLastError()) >= 32)
2103 {
2104 dprintf(("ERROR: Strange error set by CreateProcess: %d\n", hInstance ));
2105 hInstance = 11;
2106 }
2107
2108 HeapFree( GetProcessHeap(), 0, cmdline );
2109 return hInstance;
2110}
2111//******************************************************************************
2112//******************************************************************************
2113FARPROC WIN32API GetProcAddress(HMODULE hModule, LPCSTR lpszProc)
2114{
2115 Win32ImageBase *winmod;
2116 FARPROC proc;
2117 ULONG ulAPIOrdinal;
2118
2119 if(hModule == 0 || hModule == -1 || (WinExe && hModule == WinExe->getInstanceHandle())) {
2120 winmod = WinExe;
2121 }
2122 else winmod = (Win32ImageBase *)Win32DllBase::findModule((HINSTANCE)hModule);
2123
2124 if(winmod) {
2125 ulAPIOrdinal = (ULONG)lpszProc;
2126 if (ulAPIOrdinal <= 0x0000FFFF) {
2127 proc = (FARPROC)winmod->getApi((int)ulAPIOrdinal);
2128 }
2129 else proc = (FARPROC)winmod->getApi((char *)lpszProc);
2130 if(proc == 0) {
2131#ifdef DEBUG
2132 if(ulAPIOrdinal <= 0x0000FFFF) {
2133 dprintf(("GetProcAddress %x %x not found!", hModule, ulAPIOrdinal));
2134 }
2135 else dprintf(("GetProcAddress %x %s not found!", hModule, lpszProc));
2136#endif
2137 SetLastError(ERROR_PROC_NOT_FOUND);
2138 }
2139 if(HIWORD(lpszProc))
2140 dprintf(("KERNEL32: GetProcAddress %s from %X returned %X\n", lpszProc, hModule, proc));
2141 else dprintf(("KERNEL32: GetProcAddress %x from %X returned %X\n", lpszProc, hModule, proc));
2142
2143 SetLastError(ERROR_SUCCESS);
2144 return proc;
2145 }
2146 proc = (FARPROC)OSLibDosGetProcAddress(hModule, lpszProc);
2147 if(HIWORD(lpszProc))
2148 dprintf(("KERNEL32: GetProcAddress %s from %X returned %X\n", lpszProc, hModule, proc));
2149 else dprintf(("KERNEL32: GetProcAddress %x from %X returned %X\n", lpszProc, hModule, proc));
2150 SetLastError(ERROR_SUCCESS);
2151 return(proc);
2152}
2153//******************************************************************************
2154//Retrieve the version
2155//******************************************************************************
2156BOOL SYSTEM GetVersionStruct(char *lpszModName, char *verstruct, ULONG bufLength)
2157{
2158 Win32ImageBase *winimage;
2159 HINSTANCE hDll;
2160 BOOL rc = FALSE;
2161
2162 dprintf(("GetVersionStruct of module %s %x %d", lpszModName, verstruct, bufLength));
2163 if(verstruct == NULL) {
2164 SetLastError(ERROR_INVALID_PARAMETER);
2165 return FALSE;
2166 }
2167 if (WinExe != NULL && WinExe->matchModName(lpszModName)) {
2168 return WinExe->getVersionStruct(verstruct, bufLength);
2169 }
2170 hDll = LoadLibraryExA(lpszModName, 0, LOAD_LIBRARY_AS_DATAFILE);
2171 if(hDll == 0) {
2172 dprintf(("ERROR: GetVersionStruct: Unable to load module!!"));
2173 return 0;
2174 }
2175 winimage = (Win32ImageBase *)Win32DllBase::findModule(hDll);
2176 if(winimage != NULL) {
2177 rc = winimage->getVersionStruct(verstruct, bufLength);
2178 }
2179 else {
2180 dprintf(("GetVersionStruct; just loaded dll %s, but can't find it now!", lpszModName));
2181//// DebugInt3();
2182 }
2183 FreeLibrary(hDll);
2184 return rc;
2185}
2186//******************************************************************************
2187//******************************************************************************
2188ULONG SYSTEM GetVersionSize(char *lpszModName)
2189{
2190 Win32ImageBase *winimage;
2191 HINSTANCE hDll;
2192 ULONG size = 0;
2193
2194 dprintf(("GetVersionSize of %s", lpszModName));
2195 if (WinExe != NULL && WinExe->matchModName(lpszModName)) {
2196 return WinExe->getVersionSize();
2197 }
2198
2199 hDll = LoadLibraryExA(lpszModName, 0, LOAD_LIBRARY_AS_DATAFILE);
2200 if(hDll == 0) {
2201 dprintf(("ERROR: GetVersionStruct: Unable to load module!!"));
2202 return 0;
2203 }
2204 winimage = (Win32ImageBase *)Win32DllBase::findModule(hDll);
2205 if(winimage != NULL) {
2206 size = winimage->getVersionSize();
2207 }
2208 else {
2209 dprintf(("GetVersionSize; just loaded dll %s, but can't find it now!", lpszModName));
2210//// DebugInt3();
2211 }
2212 FreeLibrary(hDll);
2213 return size;
2214}
2215//******************************************************************************
2216//******************************************************************************
2217BOOL WIN32API DisableThreadLibraryCalls(HMODULE hModule)
2218{
2219 Win32DllBase *winmod;
2220 FARPROC proc;
2221 ULONG ulAPIOrdinal;
2222
2223 winmod = Win32DllBase::findModule((HINSTANCE)hModule);
2224 if(winmod)
2225 {
2226 // don't call ATTACH/DETACH thread functions in DLL
2227 winmod->disableThreadLibraryCalls();
2228 return TRUE;
2229 }
2230 else
2231 {
2232 // raise error condition
2233 SetLastError(ERROR_INVALID_HANDLE);
2234 return FALSE;
2235 }
2236}
2237//******************************************************************************
2238//******************************************************************************
Note: See TracBrowser for help on using the repository browser.