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

Last change on this file since 4562 was 4555, checked in by sandervl, 25 years ago

Use DosLoadModule instead of O32_LoadLibrary; changed log strings in exception dump (.dll/.exe)

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