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

Last change on this file since 5120 was 5075, checked in by sandervl, 25 years ago

heap (shared+code) changes + lx dll unload workaround

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