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

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

Updates for TEB changes

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