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

Last change on this file since 6830 was 6830, checked in by phaller, 24 years ago

added calldepth tracing and message buffer

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