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

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

LoadLibraryExA fix (for dlls with the same name as the exe)

File size: 71.8 KB
Line 
1/* $Id: wprocess.cpp,v 1.104 2000-10-16 11:05:15 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 BOOL fDllModule; //file type
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 NOT dll AND 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 if(strstr(lpszLibFile, ".DLL")) {
724 fDllModule = TRUE;
725 }
726 else {
727 if(!strstr(lpszLibFile, ".")) {
728 //if there's no extension or trainling dot, we
729 //assume it's a dll (see Win32 SDK docs)
730 fDllModule = TRUE;
731 }
732 }
733
734 //todo: the entire exe name probably needs to be identical (path + extension)
735 // -> check in NT
736 if (!fDllModule && WinExe != NULL && WinExe->matchModName(lpszLibFile))
737 return WinExe->getInstanceHandle();
738
739 pModule = Win32DllBase::findModule((LPSTR)lpszLibFile);
740 if (pModule)
741 {
742 pModule->incDynamicLib();
743 pModule->AddRef();
744 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Dll found %s",
745 lpszLibFile, hFile, dwFlags, pModule->getInstanceHandle(), pModule->getFullPath()));
746 return pModule->getInstanceHandle();
747 }
748
749
750 /** @sketch
751 * Test if lpszLibFile has a path or not.
752 * Copy the lpszLibFile to szModname, rename the dll and uppercase the name.
753 * IF it hasn't a path THEN
754 * Issue a findDll to find the dll/executable to be loaded.
755 * IF the Dll isn't found THEN
756 * Set last error and RETURN.
757 * Endif.
758 * Endif
759 */
760 fPath = strchr(lpszLibFile, '\\') || strchr(lpszLibFile, '/');
761 strcpy(szModname, lpszLibFile);
762 Win32DllBase::renameDll(szModname);
763 strupr(szModname);
764
765 if (!fPath)
766 {
767 char szModName2[CCHMAXPATH];
768 strcpy(szModName2, szModname);
769 if (!Win32ImageBase::findDll(szModName2, szModname, sizeof(szModname)))
770 {
771 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): module wasn't found. returns NULL",
772 lpszLibFile, hFile, dwFlags));
773 SetLastError(ERROR_FILE_NOT_FOUND);
774 return NULL;
775 }
776 }
777
778 //test if dll is in PE or LX format
779 fPE = Win32ImageBase::isPEImage(szModname, &Characteristics);
780
781 /** @sketch
782 * IF dwFlags == 0 && (!fPeLoader || !fPE) THEN
783 * Try load the executable using LoadLibrary
784 * IF successfully loaded THEN
785 * IF LX dll and is using the PE Loader THEN
786 * Set Load library.
787 * Inc reference count.
788 * Endif
789 * Inc dynamic reference count.
790 * RETURN successfully.
791 * Endif
792 * Endif
793 */
794 //only call Open32 if dwFlags == 0 and (LX binary or win32k process)
795 if(dwFlags == 0 && (!fPeLoader || fPE != ERROR_SUCCESS))
796 {
797 hDll = O32_LoadLibrary(szModname);
798 if (hDll)
799 {
800 /* OS/2 dll, system dll, converted dll or win32k took care of it. */
801 pModule = (Win32DllBase *)Win32LxDll::findModuleByOS2Handle(hDll);
802 if(pModule)
803 {
804 if(pModule->isLxDll())
805 {
806 ((Win32LxDll *)pModule)->setDllHandleOS2(hDll);
807 if(fPeLoader)
808 {
809 if(pModule->AddRef() == -1) {//-1 -> load failed (attachProcess)
810 dprintf(("Dll %s refused to be loaded; aborting", szModname));
811 delete pModule;
812 return 0;
813 }
814 }
815 }
816 pModule->incDynamicLib();
817 }
818 else
819 return hDll; //happens when LoadLibrary is called in kernel32's initterm (nor harmful)
820
821 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Loaded %s using O32_LoadLibrary.",
822 lpszLibFile, hFile, dwFlags, hDll, szModname));
823 return pModule->getInstanceHandle();
824 }
825 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): O32_LoadLibrary(%s) failed. LastError=%d",
826 lpszLibFile, hFile, dwFlags, szModname, GetLastError()));
827 }
828 else
829 hDll = NULL;
830
831
832 /** @sketch
833 * If PE image THEN
834 * IF LOAD_LIBRARY_AS_DATAFILE or Executable THEN
835 *
836 *
837 * Try load the file using the Win32PeLdrDll class.
838 * <sketch continued further down>
839 * Else
840 * Set last error.
841 * (hDll is NULL)
842 * Endif
843 * return hDll.
844 */
845 if(fPE == ERROR_SUCCESS)
846 {
847 Win32PeLdrDll *peldrDll;
848
849 //SvL: If executable -> load as data file (only resources)
850 if(!(Characteristics & IMAGE_FILE_DLL))
851 {
852 dwFlags |= (LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES);
853 }
854
855 peldrDll = new Win32PeLdrDll(szModname);
856 if (peldrDll == NULL)
857 {
858 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Failed to created instance of Win32PeLdrDll. returns NULL.",
859 lpszLibFile, hFile, dwFlags));
860 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
861 return NULL;
862 }
863
864 /** @sketch
865 * Process dwFlags
866 */
867 if (dwFlags & LOAD_LIBRARY_AS_DATAFILE)
868 {
869 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): LOAD_LIBRARY_AS_DATAFILE",
870 lpszLibFile, hFile, dwFlags));
871 peldrDll->setLoadAsDataFile();
872 peldrDll->disableLibraryCalls();
873 }
874 if (dwFlags & DONT_RESOLVE_DLL_REFERENCES)
875 {
876 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): DONT_RESOLVE_DLL_REFERENCES",
877 lpszLibFile, hFile, dwFlags));
878 peldrDll->disableLibraryCalls();
879 peldrDll->disableImportHandling();
880 }
881 if (dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH)
882 {
883 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Warning dwFlags LOAD_WITH_ALTERED_SEARCH_PATH is not implemented.",
884 lpszLibFile, hFile, dwFlags));
885 //peldrDll->setLoadWithAlteredSearchPath();
886 }
887
888 /** @sketch
889 * Initiate the peldr DLL.
890 * IF successful init THEN
891 * Inc dynamic ref count.
892 * Inc ref count.
893 * Attach to process
894 * IF successful THEN
895 * hDLL <- instance handle.
896 * ELSE
897 * set last error
898 * delete Win32PeLdrDll instance.
899 * Endif
900 * ELSE
901 * set last error
902 * delete Win32PeLdrDll instance.
903 * Endif.
904 */
905 if (peldrDll->init(0))
906 {
907 peldrDll->AddRef();
908 if (peldrDll->attachProcess())
909 {
910 hDll = peldrDll->getInstanceHandle();
911 //Must be called *after* attachprocess, since attachprocess may also
912 //trigger LoadLibrary calls
913 //Those dlls must not be put in front of this dll in the dynamic
914 //dll list; or else the unload order is wrong:
915 //i.e. RPAP3260 loads PNRS3260 in DLL_PROCESS_ATTACH
916 // this means that in ExitProcess, PNRS3260 needs to be removed
917 // first since RPAP3260 depends on it
918 peldrDll->incDynamicLib();
919 }
920 else
921 {
922 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): attachProcess call to Win32PeLdrDll instance failed. returns NULL.",
923 lpszLibFile, hFile, dwFlags));
924 SetLastError(ERROR_DLL_INIT_FAILED);
925 delete peldrDll;
926 return NULL;
927 }
928 }
929 else
930 {
931 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Failed to init Win32PeLdrDll instance. error=%d returns NULL.",
932 lpszLibFile, hFile, dwFlags, peldrDll->getError()));
933 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
934 delete peldrDll;
935 return NULL;
936 }
937 }
938 else
939 {
940 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x) library wasn't found (%s) or isn't loadable; err %x",
941 lpszLibFile, hFile, dwFlags, szModname, fPE));
942 SetLastError(fPE);
943 return NULL;
944 }
945
946 return hDll;
947}
948
949
950/**
951 * LoadLibraryExW can be used to map a DLL module into the calling process's
952 * addressspace. It returns a handle that can be used with GetProcAddress to
953 * get addresses of exported entry points (functions and variables).
954 *
955 * LoadLibraryExW can also be used to map executable (.exe) modules into the
956 * address to access resources in the module. However, LoadLibrary can't be
957 * used to run an executable (.exe) module.
958 *
959 * @returns Handle to the library which was loaded.
960 * @param lpszLibFile Pointer to Unicode string giving the name of
961 * the executable image (either a Dll or an Exe) which is to
962 * be loaded.
963 *
964 * If no extention is specified the default .DLL extention is
965 * appended to the name. End the filename with an '.' if the
966 * file does not have an extention (and don't want the .DLL
967 * appended).
968 *
969 * If no path is specified, this API will use the Odin32
970 * standard search strategy to find the file. This strategy
971 * is described in the method Win32ImageBase::findDLL.
972 * This may be alterned by the LOAD_WITH_ALTERED_SEARCH_PATH
973 * flag, see below.
974 *
975 * This API likes to have backslashes (\), but will probably
976 * accept forward slashes too. Win32 SDK docs says that it
977 * should not contain forward slashes.
978 *
979 * Win32 SDK docs adds:
980 * "The name specified is the file name of the module and
981 * is not related to the name stored in the library module
982 * itself, as specified by the LIBRARY keyword in the
983 * module-definition (.def) file."
984 *
985 * @param hFile Reserved. Must be 0.
986 *
987 * @param dwFlags Flags which specifies the taken when loading the module.
988 * The value 0 makes it identical to LoadLibraryA/W.
989 *
990 * Flags:
991 *
992 * DONT_RESOLVE_DLL_REFERENCES
993 * (WinNT/2K feature): Don't load imported modules and
994 * hence don't resolve imported symbols.
995 * DllMain isn't called either. (Which is obvious since
996 * it may use one of the importe symbols.)
997 *
998 * On the other hand, if this flag is NOT set, the system
999 * load imported modules, resolves imported symbols, calls
1000 * DllMain for process and thread init and term (if wished
1001 * by the module).
1002 *
1003 * LOAD_LIBRARY_AS_DATAFILE
1004 * If this flag is set, the module is mapped into the
1005 * address space but is not prepared for execution. Though
1006 * it's preparted for resource API. Hence, you'll use this
1007 * flag when you want to load a DLL for extracting
1008 * messages or resources from it.
1009 *
1010 * The resulting handle can be used with any Odin32 API
1011 * which operates on resources.
1012 * (WinNt/2k supports all resource APIs while Win9x don't
1013 * support the specialized resource APIs: LoadBitmap,
1014 * LoadCursor, LoadIcon, LoadImage, LoadMenu.)
1015 *
1016 * LOAD_WITH_ALTERED_SEARCH_PATH
1017 * If this flag is set and lpszLibFile specifies a path
1018 * we'll use an alternative file search strategy to find
1019 * imported modules. This stratgy is simply to use the
1020 * path of the module being loaded instead of the path
1021 * of the executable module as the first location
1022 * to search for imported modules.
1023 *
1024 * If this flag is clear, the standard Odin32 standard
1025 * search strategy. See Win32ImageBase::findDll for
1026 * further information.
1027 *
1028 * @sketch Convert Unicode name to ascii.
1029 * Call LoadLibraryExA.
1030 * Free ascii string.
1031 * return handle from LoadLibraryExA.
1032 * @status Open32 Partially Implemented.
1033 * @author Sander van Leeuwen (sandervl@xs4all.nl)
1034 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
1035 * @remark Forwards to LoadLibraryExA.
1036 */
1037HINSTANCE WIN32API LoadLibraryExW(LPCWSTR lpszLibFile, HANDLE hFile, DWORD dwFlags)
1038{
1039 char * pszAsciiLibFile;
1040 HINSTANCE hDll;
1041
1042 pszAsciiLibFile = UnicodeToAsciiString(lpszLibFile);
1043 dprintf(("KERNEL32: LoadLibraryExW(%s, 0x%x, 0x%x) --> LoadLibraryExA",
1044 pszAsciiLibFile, hFile, dwFlags));
1045 hDll = LoadLibraryExA(pszAsciiLibFile, hFile, dwFlags);
1046 dprintf(("KERNEL32: LoadLibraryExW(%s, 0x%x, 0x%x) returns 0x%x",
1047 pszAsciiLibFile, hFile, dwFlags, hDll));
1048 free(pszAsciiLibFile);
1049
1050 return hDll;
1051}
1052//******************************************************************************
1053//******************************************************************************
1054HINSTANCE16 WIN32API LoadLibrary16(LPCTSTR lpszLibFile)
1055{
1056 dprintf(("ERROR: LoadLibrary16 %s, not implemented", lpszLibFile));
1057 return 0;
1058}
1059//******************************************************************************
1060//******************************************************************************
1061VOID WIN32API FreeLibrary16(HINSTANCE16 hinstance)
1062{
1063 dprintf(("ERROR: FreeLibrary16 %x, not implemented", hinstance));
1064}
1065//******************************************************************************
1066//******************************************************************************
1067FARPROC WIN32API GetProcAddress16(HMODULE hModule, LPCSTR lpszProc)
1068{
1069 dprintf(("ERROR: GetProcAddress16 %x %x, not implemented", hModule, lpszProc));
1070 return 0;
1071}
1072
1073
1074/**
1075 * Internal function which gets the commandline (string) used to start the current process.
1076 * @returns OS/2 / Windows return code
1077 * On successful return (NO_ERROR) the global variables
1078 * pszCmdLineA and pszCmdLineW are set.
1079 *
1080 * @param pszPeExe Pass in the name of the PE exe of this process. We'll
1081 * us this as exename and skip the first argument (ie. argv[1]).
1082 * If NULL we'll use the commandline from OS/2 as it is.
1083 * @status Completely implemented and tested.
1084 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1085 */
1086ULONG InitCommandLine(const char *pszPeExe)
1087{
1088 PCHAR pib_pchcmd; /* PIB pointer to commandline. */
1089 CHAR szFilename[CCHMAXPATH]; /* Filename buffer used to get the exe filename in. */
1090 ULONG cch; /* Commandline string length. (including terminator) */
1091 PSZ psz; /* Temporary string pointer. */
1092 PSZ psz2; /* Temporary string pointer. */
1093 APIRET rc; /* OS/2 return code. */
1094 BOOL fQuotes; /* Flag used to remember if the exe filename should be in quotes. */
1095
1096 /** @sketch
1097 * Get commandline from the PIB.
1098 */
1099 pib_pchcmd = (PCHAR)OSLibGetPIB(PIB_PCHCMD);
1100
1101 /** @sketch
1102 * Two methods of making the commandline:
1103 * (1) The first argument is skipped and the second is used as exe filname.
1104 * This applies to PE.EXE launched processes only.
1105 * (2) No skipping. First argument is the exe filename.
1106 * This applies to all but PE.EXE launched processes.
1107 *
1108 * Note: We could do some code size optimization here. Much of the code for
1109 * the two methods are nearly identical.
1110 *
1111 */
1112 if(pszPeExe)
1113 {
1114 /** @sketch
1115 * Allocate memory for the commandline.
1116 * Build commandline:
1117 * Copy exe filename.
1118 * Add arguments.
1119 */
1120 cch = strlen(pszPeExe)+1;
1121 pszCmdLineA = psz = (PSZ)malloc(cch);
1122 if (psz == NULL)
1123 {
1124 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed\n", pszPeExe, cch));
1125 return ERROR_NOT_ENOUGH_MEMORY;
1126 }
1127 strcpy((char *)pszCmdLineA, pszPeExe);
1128
1129 rc = NO_ERROR;
1130 }
1131 else
1132 {
1133 /** @sketch Method (2):
1134 * First we'll have to determin the size of the commandline.
1135 *
1136 * As we don't assume that OS/2 allways puts a fully qualified EXE name
1137 * as the first string, we'll check if it's empty - and get the modulename
1138 * in that case - and allways get the fully qualified filename.
1139 */
1140 if (pib_pchcmd == NULL || pib_pchcmd[0] == '\0')
1141 {
1142 rc = OSLibDosQueryModuleName(OSLibGetPIB(PIB_HMTE), sizeof(szFilename), szFilename);
1143 if (rc != NO_ERROR)
1144 {
1145 dprintf(("KERNEL32: InitCommandLine(%p): OSLibQueryModuleName(0x%x,...) failed with rc=%d\n",
1146 pszPeExe, OSLibGetPIB(PIB_HMTE), rc));
1147 return rc;
1148 }
1149 }
1150 else
1151 {
1152 rc = OSLibDosQueryPathInfo(pib_pchcmd, FIL_QUERYFULLNAME, szFilename, sizeof(szFilename));
1153 if (rc != NO_ERROR)
1154 {
1155 dprintf(("KERNEL32: InitCommandLine(%p): (info) OSLibDosQueryPathInfo failed with rc=%d\n", pszPeExe, rc));
1156 strcpy(szFilename, pib_pchcmd);
1157 rc = NO_ERROR;
1158 }
1159 }
1160
1161 /** @sketch
1162 * We're still measuring the size of the commandline:
1163 * Check if we have to quote the exe filename.
1164 * Determin the length of the executable name including quotes and '\0'-terminator.
1165 * Count the length of the arguments. (We here count's all argument strings.)
1166 */
1167 fQuotes = strchr(szFilename, ' ') != NULL;
1168 cch = strlen(szFilename) + fQuotes*2 + 1;
1169 if (pib_pchcmd != NULL)
1170 {
1171 psz2 = pib_pchcmd + strlen(pib_pchcmd) + 1;
1172 while (*psz2 != '\0')
1173 {
1174 register int cchTmp = strlen(psz2) + 1; /* + 1 is for terminator (psz2) and space (cch). */
1175 psz2 += cchTmp;
1176 cch += cchTmp;
1177 }
1178 }
1179
1180 /** @sketch
1181 * Allocate memory for the commandline.
1182 * Build commandline:
1183 * Copy exe filename.
1184 * Add arguments.
1185 */
1186 pszCmdLineA = psz = (PSZ)malloc(cch);
1187 if (psz == NULL)
1188 {
1189 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed\n", pszPeExe, cch));
1190 return ERROR_NOT_ENOUGH_MEMORY;
1191 }
1192
1193 if (fQuotes)
1194 *psz++ = '"';
1195 strcpy(psz, szFilename);
1196 psz += strlen(psz);
1197 if (fQuotes)
1198 {
1199 *psz++ = '"';
1200 *psz = '\0';
1201 }
1202
1203 if (pib_pchcmd != NULL)
1204 {
1205 psz2 = pib_pchcmd + strlen(pib_pchcmd) + 1;
1206 while (*psz2 != '\0')
1207 {
1208 register int cchTmp = strlen(psz2) + 1; /* + 1 is for terminator (psz). */
1209 *psz++ = ' '; /* add space */
1210 memcpy(psz, psz2, cchTmp);
1211 psz2 += cchTmp;
1212 psz += cchTmp - 1;
1213 }
1214 }
1215 }
1216
1217 /** @sketch
1218 * If successfully build ASCII commandline then convert it to UniCode.
1219 */
1220 if (rc == NO_ERROR)
1221 {
1222 pszCmdLineW = (WCHAR*)malloc(cch * 2);
1223 if (pszCmdLineW != NULL)
1224 AsciiToUnicode(pszCmdLineA, (WCHAR*)pszCmdLineW);
1225 else
1226 {
1227 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed (2)\n", pszPeExe, cch));
1228 rc = ERROR_NOT_ENOUGH_MEMORY;
1229 }
1230 }
1231
1232 return rc;
1233}
1234
1235/**
1236 * Gets the command line of the current process.
1237 * @returns On success:
1238 * Command line of the current process. One single string.
1239 * The first part of the command line string is the executable filename
1240 * of the current process. It might be in quotes if it contains spaces.
1241 * The rest of the string is arguments.
1242 *
1243 * On error:
1244 * NULL. Last error set. (does Win32 set last error this?)
1245 * @sketch IF not inited THEN
1246 * Init commandline assuming !PE.EXE
1247 * IF init failes THEN set last error.
1248 * ENDIF
1249 * return ASCII/ANSI commandline.
1250 * @status Completely implemented and tested.
1251 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1252 * @remark The Ring-3 PeLdr is resposible for calling InitCommandLine before anyone
1253 * is able to call this function.
1254 */
1255LPCSTR WIN32API GetCommandLineA(VOID)
1256{
1257 /*
1258 * Check if the commandline is initiated.
1259 * If not we'll have to do it.
1260 * ASSUMES that if not inited this isn't a PE.EXE lauched process.
1261 */
1262 if (pszCmdLineA == NULL)
1263 {
1264 APIRET rc;
1265 rc = InitCommandLine(NULL);
1266 if (rc != NULL)
1267 SetLastError(rc);
1268 }
1269
1270 dprintf(("KERNEL32: GetCommandLineA: %s\n", pszCmdLineA));
1271 return pszCmdLineA;
1272}
1273
1274
1275/**
1276 * Gets the command line of the current process.
1277 * @returns On success:
1278 * Command line of the current process. One single string.
1279 * The first part of the command line string is the executable filename
1280 * of the current process. It might be in quotes if it contains spaces.
1281 * The rest of the string is arguments.
1282 *
1283 * On error:
1284 * NULL. Last error set. (does Win32 set last error this?)
1285 * @sketch IF not inited THEN
1286 * Init commandline assuming !PE.EXE
1287 * IF init failes THEN set last error.
1288 * ENDIF
1289 * return Unicode commandline.
1290 * @status Completely implemented and tested.
1291 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1292 * @remark The Ring-3 PeLdr is resposible for calling InitCommandLine before anyone
1293 * is able to call this function.
1294 */
1295LPCWSTR WIN32API GetCommandLineW(void)
1296{
1297 /*
1298 * Check if the commandline is initiated.
1299 * If not we'll have to do it.
1300 * ASSUMES that if not inited this isn't a PE.EXE lauched process.
1301 */
1302 if (pszCmdLineW == NULL)
1303 {
1304 APIRET rc;
1305 rc = InitCommandLine(NULL);
1306 if (rc != NULL)
1307 SetLastError(rc);
1308 }
1309
1310 dprintf(("KERNEL32: GetCommandLineW: %s\n", pszCmdLineA));
1311 return pszCmdLineW;
1312}
1313
1314
1315/**
1316 * GetModuleFileName gets the full path and file name for the specified module.
1317 * @returns Bytes written to the buffer (lpszPath). This count includes the
1318 * terminating '\0'.
1319 * On error 0 is returned. Last error is set.
1320 * @param hModule Handle to the module you like to get the file name to.
1321 * @param lpszPath Output buffer for full path and file name.
1322 * @param cchPath Size of the lpszPath buffer.
1323 * @sketch Validate lpszPath.
1324 * Find the module object using handle.
1325 * If found Then
1326 * Get full path from module object.
1327 * If found path Then
1328 * Copy path to buffer and set the number of bytes written.
1329 * Else
1330 * IPE!
1331 * Else
1332 * Call Open32 GetModuleFileName. (kernel32 initterm needs/needed this)
1333 * Log result.
1334 * Return number of bytes written to the buffer.
1335 *
1336 * @status Completely implemented, Open32.
1337 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1338 * Sander van Leeuwen (sandervl@xs4all.nl)
1339 * @remark - Do we still have to call Open32?
1340 * - Do we set ERROR_BUFFER_OVERFLOW when cch > cchPath?
1341 * - Does NT really set the last error?
1342 */
1343DWORD WIN32API GetModuleFileNameA(HMODULE hModule, LPTSTR lpszPath, DWORD cchPath)
1344{
1345 Win32ImageBase * pMod; /* Pointer to the module object. */
1346 DWORD cch; /* Length of the */
1347
1348 if (!VALID_PSZ(lpszPath))
1349 {
1350 dprintf(("KERNEL32: GetModuleFileNameA(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
1351 hModule, lpszPath, cchPath, lpszPath));
1352 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
1353 return 0;
1354 }
1355
1356 pMod = Win32ImageBase::findModule(hModule);
1357 if (pMod != NULL)
1358 {
1359 const char *pszFn = pMod->getFullPath();
1360 if (pszFn)
1361 {
1362 cch = strlen(pszFn) + 1;
1363 if (cch > cchPath)
1364 cch = cchPath;
1365 memcpy(lpszPath, pszFn, cch);
1366 lpszPath[cch - 1] = '\0';
1367 }
1368 else
1369 {
1370 dprintf(("KERNEL32: GetModuleFileNameA(%x,...): IPE - getFullPath returned NULL or empty string\n"));
1371 DebugInt3();
1372 SetLastError(ERROR_INVALID_HANDLE);
1373 }
1374 }
1375 else
1376 {
1377 SetLastError(ERROR_INVALID_HANDLE);
1378 //only needed for call inside kernel32's initterm (profile init)
1379 //(console init only it seems...)
1380 cch = O32_GetModuleFileName(hModule, lpszPath, cchPath);
1381 if (cch > 0) cch++; /* Open32 doesn't count the terminator. */
1382 }
1383
1384 if (cch > 0)
1385 dprintf(("KERNEL32: GetModuleFileNameA(%x %x): %s %d\n", hModule, lpszPath, lpszPath, cch));
1386 else
1387 dprintf(("KERNEL32: WARNING: GetModuleFileNameA(%x,...) - not found!", hModule));
1388
1389 return cch;
1390}
1391
1392
1393/**
1394 * GetModuleFileName gets the full path and file name for the specified module.
1395 * @returns Bytes written to the buffer (lpszPath). This count includes the
1396 * terminating '\0'.
1397 * On error 0 is returned. Last error is set.
1398 * @param hModule Handle to the module you like to get the file name to.
1399 * @param lpszPath Output buffer for full path and file name.
1400 * @param cchPath Size of the lpszPath buffer.
1401 * @sketch Find the module object using handle.
1402 * If found Then
1403 * get full path from module object.
1404 * If found path Then
1405 * Determin path length.
1406 * Translate the path to into the buffer.
1407 * Else
1408 * IPE.
1409 * else
1410 * SetLastError to invalid handle.
1411 * Log result.
1412 * return number of bytes written to the buffer.
1413 *
1414 * @status Completely implemented.
1415 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1416 * @remark - We do _NOT_ call Open32.
1417 * - Do we set ERROR_BUFFER_OVERFLOW when cch > cchPath?
1418 * - Does NT really set the last error?
1419 */
1420DWORD WIN32API GetModuleFileNameW(HMODULE hModule, LPWSTR lpszPath, DWORD cchPath)
1421{
1422 Win32ImageBase * pMod;
1423 DWORD cch = 0;
1424
1425 if (!VALID_PSZ(lpszPath))
1426 {
1427 dprintf(("KERNEL32: GetModuleFileNameW(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
1428 hModule, lpszPath, cchPath, lpszPath));
1429 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
1430 return 0;
1431 }
1432
1433 pMod = Win32ImageBase::findModule(hModule);
1434 if (pMod != NULL)
1435 {
1436 const char *pszFn = pMod->getFullPath();
1437 if (pszFn || *pszFn != '\0')
1438 {
1439 cch = strlen(pszFn) + 1;
1440 if (cch > cchPath)
1441 cch = cchPath;
1442 AsciiToUnicodeN(pszFn, lpszPath, cch);
1443 }
1444 else
1445 {
1446 dprintf(("KERNEL32: GetModuleFileNameW(%x,...): IPE - getFullPath returned NULL or empty string\n"));
1447 DebugInt3();
1448 SetLastError(ERROR_INVALID_HANDLE);
1449 }
1450 }
1451 else
1452 SetLastError(ERROR_INVALID_HANDLE);
1453
1454 if (cch > 0)
1455 dprintf(("KERNEL32: GetModuleFileNameW(%x,...): %s %d\n", hModule, lpszPath, cch));
1456 else
1457 dprintf(("KERNEL32: WARNING: GetModuleFileNameW(%x,...) - not found!", hModule));
1458
1459 return cch;
1460}
1461
1462
1463//******************************************************************************
1464//NOTE: GetModuleHandleA does NOT support files with multiple dots (i.e.
1465// very.weird.exe)
1466//******************************************************************************
1467HANDLE WIN32API GetModuleHandleA(LPCTSTR lpszModule)
1468{
1469 HANDLE hMod = 0;
1470 Win32DllBase *windll;
1471 char szModule[CCHMAXPATH];
1472 BOOL fDllModule = FALSE;
1473
1474 if(lpszModule == NULL) {
1475 if(WinExe)
1476 hMod = WinExe->getInstanceHandle();
1477 else hMod = -1;
1478 }
1479 else
1480 {
1481 strcpy(szModule, OSLibStripPath((char *)lpszModule));
1482 strupr(szModule);
1483 if(strstr(szModule, ".DLL")) {
1484 fDllModule = TRUE;
1485 }
1486 else {
1487 if(!strstr(szModule, ".")) {
1488 //if there's no extension or trainling dot, we
1489 //assume it's a dll (see Win32 SDK docs)
1490 fDllModule = TRUE;
1491 }
1492 }
1493 char *dot = strstr(szModule, ".");
1494 if(dot)
1495 *dot = 0;
1496
1497 if(!fDllModule && WinExe && WinExe->matchModName(szModule)) {
1498 hMod = WinExe->getInstanceHandle();
1499 }
1500 else {
1501 windll = Win32DllBase::findModule(szModule);
1502 if(windll) {
1503 hMod = windll->getInstanceHandle();
1504 }
1505 }
1506 }
1507
1508 dprintf(("KERNEL32: GetModuleHandle %s returned %X\n", lpszModule, hMod));
1509 return(hMod);
1510}
1511//******************************************************************************
1512//******************************************************************************
1513HMODULE WIN32API GetModuleHandleW(LPCWSTR arg1)
1514{
1515 HMODULE rc;
1516 char *astring;
1517
1518 astring = UnicodeToAsciiString((LPWSTR)arg1);
1519 rc = GetModuleHandleA(astring);
1520 dprintf(("KERNEL32: OS2GetModuleHandleW %s returned %X\n", astring, rc));
1521 FreeAsciiString(astring);
1522 return(rc);
1523}
1524//******************************************************************************
1525//******************************************************************************
1526BOOL WINAPI CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine,
1527 LPSECURITY_ATTRIBUTES lpProcessAttributes,
1528 LPSECURITY_ATTRIBUTES lpThreadAttributes,
1529 BOOL bInheritHandles, DWORD dwCreationFlags,
1530 LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
1531 LPSTARTUPINFOA lpStartupInfo,
1532 LPPROCESS_INFORMATION lpProcessInfo )
1533{
1534 THDB *pThreadDB = (THDB*)GetThreadTHDB();
1535 char *cmdline = NULL;
1536 BOOL rc;
1537
1538 dprintf(("KERNEL32: CreateProcessA %s cline:%s inherit:%d cFlags:%x Env:%x CurDir:%s StartupFlags:%x\n",
1539 lpApplicationName, lpCommandLine, bInheritHandles, dwCreationFlags,
1540 lpEnvironment, lpCurrentDirectory, lpStartupInfo));
1541
1542 // open32 does not support DEBUG_ONLY_THIS_PROCESS
1543 if(dwCreationFlags & DEBUG_ONLY_THIS_PROCESS)
1544 dwCreationFlags |= DEBUG_PROCESS;
1545
1546 if(O32_CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes,
1547 lpThreadAttributes, bInheritHandles, dwCreationFlags,
1548 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
1549 lpProcessInfo) == TRUE)
1550 {
1551 if (dwCreationFlags & DEBUG_PROCESS && pThreadDB != NULL)
1552 {
1553 if(pThreadDB->pidDebuggee != 0)
1554 {
1555 // TODO: handle this
1556 dprintf(("KERNEL32: CreateProcess ERROR: This thread is already a debugger\n"));
1557 }
1558 else
1559 {
1560 pThreadDB->pidDebuggee = lpProcessInfo->dwProcessId;
1561 OSLibStartDebugger((ULONG*)&pThreadDB->pidDebuggee);
1562 }
1563 }
1564 else pThreadDB->pidDebuggee = 0;
1565
1566 return(TRUE);
1567 }
1568 //probably a win32 exe, so run it in the pe loader
1569 if(lpApplicationName) {
1570 if(lpCommandLine) {
1571 //skip exe name in lpCommandLine
1572 //TODO: doesn't work for directories with spaces!
1573 while(*lpCommandLine != 0 && *lpCommandLine != ' ')
1574 lpCommandLine++;
1575
1576 if(*lpCommandLine != 0) {
1577 lpCommandLine++;
1578 }
1579 cmdline = (char *)malloc(strlen(lpApplicationName)+strlen(lpCommandLine) + 16);
1580 sprintf(cmdline, "%s %s", lpApplicationName, lpCommandLine);
1581 }
1582 else {
1583 cmdline = (char *)malloc(strlen(lpApplicationName) + 16);
1584 sprintf(cmdline, "%s", lpApplicationName);
1585 }
1586 }
1587 else {
1588 cmdline = (char *)malloc(strlen(lpCommandLine) + 16);
1589 sprintf(cmdline, "%s", lpCommandLine);
1590 }
1591 char szAppName[255];
1592 char *exename = szAppName;
1593 strncpy(szAppName, cmdline, sizeof(szAppName));
1594 szAppName[254] = 0;
1595 if(*exename == '"') {
1596 exename++;
1597 }
1598
1599 //TODO: doesn't work for directories with spaces!
1600 while(*exename != 0 && *exename != ' ' && *exename != '"')
1601 exename++;
1602
1603 if(*exename != 0) {
1604 *exename = 0;
1605 }
1606 if(szAppName[0] == '"') {
1607 exename = &szAppName[1];
1608 }
1609 else exename = szAppName;
1610
1611 if(GetFileAttributesA(exename) == -1) {
1612 dprintf(("CreateProcess: can't find executable!"));
1613 SetLastError(ERROR_FILE_NOT_FOUND);
1614 return FALSE;
1615 }
1616 dprintf(("KERNEL32: CreateProcess %s\n", cmdline));
1617
1618 //SvL: Allright. Before we call O32_CreateProcess, we must take care of
1619 // lpCurrentDirectory ourselves. (Open32 ignores it!)
1620 if(lpCurrentDirectory) {
1621 char *newcmdline;
1622
1623 newcmdline = (char *)malloc(strlen(lpCurrentDirectory) + strlen(cmdline) + 32);
1624 sprintf(newcmdline, "PE.EXE /OPT:[CURDIR=%s] %s", lpCurrentDirectory, cmdline);
1625 free(cmdline);
1626 cmdline = newcmdline;
1627 }
1628 else {
1629 char *newcmdline;
1630
1631 newcmdline = (char *)malloc(strlen(cmdline) + 16);
1632 sprintf(newcmdline, "PE.EXE %s", cmdline);
1633 free(cmdline);
1634 cmdline = newcmdline;
1635 }
1636 rc = O32_CreateProcess("PE.EXE", (LPCSTR)cmdline,lpProcessAttributes,
1637 lpThreadAttributes, bInheritHandles, dwCreationFlags,
1638 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
1639 lpProcessInfo);
1640 if(rc == TRUE)
1641 {
1642 if (dwCreationFlags & DEBUG_PROCESS && pThreadDB != NULL)
1643 {
1644 if(pThreadDB->pidDebuggee != 0)
1645 {
1646 // TODO: handle this
1647 dprintf(("KERNEL32: CreateProcess ERROR: This thread is already a debugger\n"));
1648 }
1649 else
1650 {
1651 pThreadDB->pidDebuggee = lpProcessInfo->dwProcessId;
1652 OSLibStartDebugger((ULONG*)&pThreadDB->pidDebuggee);
1653 }
1654 }
1655 else
1656 pThreadDB->pidDebuggee = 0;
1657 }
1658 if(cmdline)
1659 free(cmdline);
1660
1661 if(lpProcessInfo)
1662 dprintf(("KERNEL32: CreateProcess returned %d hPro:%x hThr:%x pid:%x tid:%x\n",
1663 rc, lpProcessInfo->hProcess, lpProcessInfo->hThread,
1664 lpProcessInfo->dwProcessId,lpProcessInfo->dwThreadId));
1665 else
1666 dprintf(("KERNEL32: CreateProcess returned %d\n", rc));
1667 return(rc);
1668}
1669//******************************************************************************
1670//******************************************************************************
1671BOOL WIN32API CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
1672 PSECURITY_ATTRIBUTES lpProcessAttributes,
1673 PSECURITY_ATTRIBUTES lpThreadAttributes,
1674 BOOL bInheritHandles, DWORD dwCreationFlags,
1675 LPVOID lpEnvironment,
1676 LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
1677 LPPROCESS_INFORMATION lpProcessInfo)
1678{
1679 BOOL rc;
1680 char *astring1 = 0, *astring2 = 0, *astring3 = 0;
1681
1682 dprintf(("KERNEL32: CreateProcessW"));
1683 if(lpApplicationName)
1684 astring1 = UnicodeToAsciiString((LPWSTR)lpApplicationName);
1685 if(lpCommandLine)
1686 astring2 = UnicodeToAsciiString(lpCommandLine);
1687 if(lpCurrentDirectory)
1688 astring3 = UnicodeToAsciiString((LPWSTR)lpCurrentDirectory);
1689 rc = CreateProcessA(astring1, astring2, lpProcessAttributes, lpThreadAttributes,
1690 bInheritHandles, dwCreationFlags, lpEnvironment,
1691 astring3, (LPSTARTUPINFOA)lpStartupInfo,
1692 lpProcessInfo);
1693 if(astring3) FreeAsciiString(astring3);
1694 if(astring2) FreeAsciiString(astring2);
1695 if(astring1) FreeAsciiString(astring1);
1696 return(rc);
1697}
1698//******************************************************************************
1699//******************************************************************************
1700HINSTANCE WIN32API WinExec(LPCSTR lpCmdLine, UINT nCmdShow)
1701{
1702 STARTUPINFOA startinfo = {0};
1703 PROCESS_INFORMATION procinfo;
1704 DWORD rc;
1705
1706 dprintf(("KERNEL32: WinExec %s\n", lpCmdLine));
1707 startinfo.dwFlags = nCmdShow;
1708 if(CreateProcessA(NULL, (LPSTR)lpCmdLine, NULL, NULL, FALSE, 0, NULL, NULL,
1709 &startinfo, &procinfo) == FALSE)
1710 {
1711 return 0;
1712 }
1713 //block until the launched app waits for input (or a timeout of 15 seconds)
1714 //TODO: Shouldn't call Open32, but the api in user32..
1715 rc = O32_WaitForInputIdle(procinfo.hProcess, 15000);
1716 if(rc != 0) {
1717 dprintf(("WinExec: WaitForInputIdle %x returned %x", procinfo.hProcess, rc));
1718 }
1719 return procinfo.hProcess; //correct?
1720}
1721/**********************************************************************
1722 * LoadModule (KERNEL32.499)
1723 *
1724 * Wine: 20000909
1725 *
1726 * Copyright 1995 Alexandre Julliard
1727 */
1728HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock )
1729{
1730 LOADPARAMS *params = (LOADPARAMS *)paramBlock;
1731 PROCESS_INFORMATION info;
1732 STARTUPINFOA startup;
1733 HINSTANCE hInstance;
1734 LPSTR cmdline, p;
1735 char filename[MAX_PATH];
1736 BYTE len;
1737
1738 dprintf(("LoadModule %s %x", name, paramBlock));
1739
1740 if (!name) return ERROR_FILE_NOT_FOUND;
1741
1742 if (!SearchPathA( NULL, name, ".exe", sizeof(filename), filename, NULL ) &&
1743 !SearchPathA( NULL, name, NULL, sizeof(filename), filename, NULL ))
1744 return GetLastError();
1745
1746 len = (BYTE)params->lpCmdLine[0];
1747 if (!(cmdline = (LPSTR)HeapAlloc( GetProcessHeap(), 0, strlen(filename) + len + 2 )))
1748 return ERROR_NOT_ENOUGH_MEMORY;
1749
1750 strcpy( cmdline, filename );
1751 p = cmdline + strlen(cmdline);
1752 *p++ = ' ';
1753 memcpy( p, params->lpCmdLine + 1, len );
1754 p[len] = 0;
1755
1756 memset( &startup, 0, sizeof(startup) );
1757 startup.cb = sizeof(startup);
1758 if (params->lpCmdShow)
1759 {
1760 startup.dwFlags = STARTF_USESHOWWINDOW;
1761 startup.wShowWindow = params->lpCmdShow[1];
1762 }
1763
1764 if (CreateProcessA( filename, cmdline, NULL, NULL, FALSE, 0,
1765 params->lpEnvAddress, NULL, &startup, &info ))
1766 {
1767 /* Give 15 seconds to the app to come up */
1768 if ( O32_WaitForInputIdle ( info.hProcess, 15000 ) == 0xFFFFFFFF )
1769 dprintf(("ERROR: WaitForInputIdle failed: Error %ld\n", GetLastError() ));
1770 hInstance = 33;
1771 /* Close off the handles */
1772 CloseHandle( info.hThread );
1773 CloseHandle( info.hProcess );
1774 }
1775 else if ((hInstance = GetLastError()) >= 32)
1776 {
1777 dprintf(("ERROR: Strange error set by CreateProcess: %d\n", hInstance ));
1778 hInstance = 11;
1779 }
1780
1781 HeapFree( GetProcessHeap(), 0, cmdline );
1782 return hInstance;
1783}
1784//******************************************************************************
1785//******************************************************************************
1786FARPROC WIN32API GetProcAddress(HMODULE hModule, LPCSTR lpszProc)
1787{
1788 Win32ImageBase *winmod;
1789 FARPROC proc;
1790 ULONG ulAPIOrdinal;
1791
1792 if(hModule == 0 || hModule == -1 || (WinExe && hModule == WinExe->getInstanceHandle())) {
1793 winmod = WinExe;
1794 }
1795 else winmod = (Win32ImageBase *)Win32DllBase::findModule((HINSTANCE)hModule);
1796
1797 if(winmod) {
1798 ulAPIOrdinal = (ULONG)lpszProc;
1799 if (ulAPIOrdinal <= 0x0000FFFF) {
1800 proc = (FARPROC)winmod->getApi((int)ulAPIOrdinal);
1801 }
1802 else proc = (FARPROC)winmod->getApi((char *)lpszProc);
1803 if(proc == 0) {
1804#ifdef DEBUG
1805 if(ulAPIOrdinal <= 0x0000FFFF) {
1806 dprintf(("GetProcAddress %x %x not found!", hModule, ulAPIOrdinal));
1807 }
1808 else dprintf(("GetProcAddress %x %s not found!", hModule, lpszProc));
1809#endif
1810 SetLastError(ERROR_PROC_NOT_FOUND);
1811 }
1812 if(HIWORD(lpszProc))
1813 dprintf(("KERNEL32: GetProcAddress %s from %X returned %X\n", lpszProc, hModule, proc));
1814 else dprintf(("KERNEL32: GetProcAddress %x from %X returned %X\n", lpszProc, hModule, proc));
1815 return proc;
1816 }
1817 proc = O32_GetProcAddress(hModule, lpszProc);
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//******************************************************************************
1824//Retrieve the version
1825//******************************************************************************
1826BOOL SYSTEM GetVersionStruct(char *lpszModName, char *verstruct, ULONG bufLength)
1827{
1828 Win32ImageBase *winimage;
1829 HINSTANCE hDll;
1830
1831 dprintf(("GetVersionStruct of module %s %x %d", lpszModName, verstruct, bufLength));
1832 if(verstruct == NULL) {
1833 SetLastError(ERROR_INVALID_PARAMETER);
1834 return FALSE;
1835 }
1836 if(WinExe && !stricmp(WinExe->getFullPath(), lpszModName))
1837 {
1838 winimage = (Win32ImageBase *)WinExe;
1839 }
1840 else
1841 {
1842 winimage = (Win32ImageBase *)Win32DllBase::findModule(lpszModName);
1843 if(winimage == NULL)
1844 {
1845 char modname[CCHMAXPATH];
1846
1847 strcpy(modname, lpszModName);
1848 //rename dll if necessary (i.e. OLE32 -> OLE32OS2)
1849 Win32DllBase::renameDll(modname);
1850
1851 if(Win32ImageBase::isPEImage(modname) != ERROR_SUCCESS)
1852 {
1853 HINSTANCE hInstance;
1854
1855 //must be an LX dll, just load it (app will probably load it anyway)
1856 hInstance = LoadLibraryA(modname);
1857 if(hInstance == 0)
1858 return 0;
1859
1860 winimage = (Win32ImageBase *)Win32DllBase::findModule(hInstance);
1861 if(winimage) {
1862 return winimage->getVersionStruct(verstruct, bufLength);
1863 }
1864 dprintf(("GetVersionStruct; just loaded dll %s, but can't find it now!", modname));
1865 return 0;
1866 }
1867 BOOL rc = FALSE;
1868
1869 hDll = LoadLibraryExA(lpszModName, 0, LOAD_LIBRARY_AS_DATAFILE);
1870 if(hDll == 0)
1871 return 0;
1872
1873 winimage = (Win32ImageBase *)Win32DllBase::findModule(lpszModName);
1874 if(winimage != NULL) {
1875 rc = winimage->getVersionStruct(verstruct, bufLength);
1876 }
1877 else dprintf(("GetVersionSize; just loaded dll %s, but can't find it now!", lpszModName));
1878 FreeLibrary(hDll);
1879 return rc;
1880 }
1881 }
1882 return winimage->getVersionStruct(verstruct, bufLength);
1883}
1884//******************************************************************************
1885//******************************************************************************
1886ULONG SYSTEM GetVersionSize(char *lpszModName)
1887{
1888 Win32ImageBase *winimage;
1889 HINSTANCE hDll;
1890
1891 dprintf(("GetVersionSize of %s\n", lpszModName));
1892
1893 if(WinExe && !stricmp(WinExe->getFullPath(), lpszModName)) {
1894 winimage = (Win32ImageBase *)WinExe;
1895 }
1896 else {
1897 winimage = (Win32ImageBase *)Win32DllBase::findModule(lpszModName);
1898 if(winimage == NULL)
1899 {
1900 char modname[CCHMAXPATH];
1901
1902 strcpy(modname, lpszModName);
1903 //rename dll if necessary (i.e. OLE32 -> OLE32OS2)
1904 Win32DllBase::renameDll(modname);
1905
1906 if(Win32ImageBase::isPEImage(modname) != ERROR_SUCCESS)
1907 {
1908 HINSTANCE hInstance;
1909
1910 //must be an LX dll, just load it (app will probably load it anyway)
1911 hInstance = LoadLibraryA(modname);
1912 if(hInstance == 0)
1913 return 0;
1914
1915 winimage = (Win32ImageBase *)Win32DllBase::findModule(hInstance);
1916 if(winimage) {
1917 return winimage->getVersionSize();
1918 }
1919 dprintf(("GetVersionSize; just loaded dll %s, but can't find it now!", modname));
1920 return 0;
1921 }
1922 int size = 0;
1923
1924 hDll = LoadLibraryExA(lpszModName, 0, LOAD_LIBRARY_AS_DATAFILE);
1925 if(hDll == 0)
1926 return 0;
1927
1928 winimage = (Win32ImageBase *)Win32DllBase::findModule(lpszModName);
1929 if(winimage != NULL) {
1930 size = winimage->getVersionSize();
1931 }
1932 else dprintf(("GetVersionSize; just loaded dll %s, but can't find it now!", lpszModName));
1933 FreeLibrary(hDll);
1934 return size;
1935 }
1936 }
1937 return winimage->getVersionSize();
1938}
1939//******************************************************************************
1940//******************************************************************************
1941ODINFUNCTION1(BOOL,DisableThreadLibraryCalls,HMODULE,hModule)
1942{
1943 Win32DllBase *winmod;
1944 FARPROC proc;
1945 ULONG ulAPIOrdinal;
1946
1947 winmod = Win32DllBase::findModule((HINSTANCE)hModule);
1948 if(winmod)
1949 {
1950 // don't call ATTACH/DETACH thread functions in DLL
1951 winmod->disableThreadLibraryCalls();
1952 return TRUE;
1953 }
1954 else
1955 {
1956 // raise error condition
1957 SetLastError(ERROR_INVALID_HANDLE);
1958 return FALSE;
1959 }
1960}
1961//******************************************************************************
1962//******************************************************************************
Note: See TracBrowser for help on using the repository browser.