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

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

lstrcpynAtoW/WtoA bugfix (string termination)

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