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

Last change on this file since 5308 was 5308, checked in by sandervl, 24 years ago

removed builtin.h include + initterm update

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