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

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

odininst update, CreateProcess fix & workaround for PM hang in WaitForSingleObject (process handle)

File size: 70.9 KB
Line 
1/* $Id: wprocess.cpp,v 1.111 2001-01-14 17:16:55 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
1571 char szAppName[255];
1572 DWORD fileAttr;
1573 char *exename = szAppName;
1574 strncpy(szAppName, cmdline, sizeof(szAppName));
1575 szAppName[254] = 0;
1576 if(*exename == '"') {
1577 exename++;
1578 while(*exename != 0 && *exename != '"')
1579 exename++;
1580
1581 if(*exename != 0) {
1582 *exename = 0;
1583 }
1584 exename = &szAppName[1];
1585 }
1586 else {
1587 BOOL fTerminate = FALSE;
1588 DWORD fileAttr;
1589
1590 //TODO: doesn't work for directories with spaces!
1591 while(*exename != 0) {
1592 while(*exename != 0 && *exename != ' ')
1593 exename++;
1594
1595 if(*exename != 0) {
1596 *exename = 0;
1597 fTerminate = TRUE;
1598 }
1599
1600 fileAttr = GetFileAttributesA(szAppName);
1601 if(fileAttr != -1 && !(fileAttr & FILE_ATTRIBUTE_DIRECTORY)) {
1602 break;
1603 }
1604 if(fTerminate) {
1605 *exename = ' ';
1606 exename++;
1607 fTerminate = FALSE;
1608 }
1609 }
1610 exename = szAppName;
1611 }
1612 fileAttr = GetFileAttributesA(exename);
1613 if(fileAttr == -1 || (fileAttr & FILE_ATTRIBUTE_DIRECTORY)) {
1614 dprintf(("CreateProcess: can't find executable!"));
1615 SetLastError(ERROR_FILE_NOT_FOUND);
1616 return FALSE;
1617 }
1618
1619 dprintf(("KERNEL32: CreateProcess %s\n", cmdline));
1620
1621 //SvL: Allright. Before we call O32_CreateProcess, we must take care of
1622 // lpCurrentDirectory ourselves. (Open32 ignores it!)
1623 if(lpCurrentDirectory) {
1624 char *newcmdline;
1625
1626 newcmdline = (char *)malloc(strlen(lpCurrentDirectory) + strlen(cmdline) + 32);
1627 sprintf(newcmdline, "PE.EXE /OPT:[CURDIR=%s] %s", lpCurrentDirectory, cmdline);
1628 free(cmdline);
1629 cmdline = newcmdline;
1630 }
1631 else {
1632 char *newcmdline;
1633
1634 newcmdline = (char *)malloc(strlen(cmdline) + 16);
1635 sprintf(newcmdline, "PE.EXE %s", cmdline);
1636 free(cmdline);
1637 cmdline = newcmdline;
1638 }
1639 rc = O32_CreateProcess("PE.EXE", (LPCSTR)cmdline,lpProcessAttributes,
1640 lpThreadAttributes, bInheritHandles, dwCreationFlags,
1641 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
1642 lpProcessInfo);
1643 if(rc == TRUE)
1644 {
1645 if (dwCreationFlags & DEBUG_PROCESS && pThreadDB != NULL)
1646 {
1647 if(pThreadDB->o.odin.pidDebuggee != 0)
1648 {
1649 // TODO: handle this
1650 dprintf(("KERNEL32: CreateProcess ERROR: This thread is already a debugger\n"));
1651 }
1652 else
1653 {
1654 pThreadDB->o.odin.pidDebuggee = lpProcessInfo->dwProcessId;
1655 OSLibStartDebugger((ULONG*)&pThreadDB->o.odin.pidDebuggee);
1656 }
1657 }
1658 else
1659 pThreadDB->o.odin.pidDebuggee = 0;
1660 }
1661 if(cmdline)
1662 free(cmdline);
1663
1664 if(lpProcessInfo)
1665 dprintf(("KERNEL32: CreateProcess returned %d hPro:%x hThr:%x pid:%x tid:%x\n",
1666 rc, lpProcessInfo->hProcess, lpProcessInfo->hThread,
1667 lpProcessInfo->dwProcessId,lpProcessInfo->dwThreadId));
1668 else
1669 dprintf(("KERNEL32: CreateProcess returned %d\n", rc));
1670 return(rc);
1671}
1672//******************************************************************************
1673//******************************************************************************
1674BOOL WIN32API CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
1675 PSECURITY_ATTRIBUTES lpProcessAttributes,
1676 PSECURITY_ATTRIBUTES lpThreadAttributes,
1677 BOOL bInheritHandles, DWORD dwCreationFlags,
1678 LPVOID lpEnvironment,
1679 LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
1680 LPPROCESS_INFORMATION lpProcessInfo)
1681{
1682 BOOL rc;
1683 char *astring1 = 0, *astring2 = 0, *astring3 = 0;
1684
1685 dprintf(("KERNEL32: CreateProcessW"));
1686 if(lpApplicationName)
1687 astring1 = UnicodeToAsciiString((LPWSTR)lpApplicationName);
1688 if(lpCommandLine)
1689 astring2 = UnicodeToAsciiString(lpCommandLine);
1690 if(lpCurrentDirectory)
1691 astring3 = UnicodeToAsciiString((LPWSTR)lpCurrentDirectory);
1692 rc = CreateProcessA(astring1, astring2, lpProcessAttributes, lpThreadAttributes,
1693 bInheritHandles, dwCreationFlags, lpEnvironment,
1694 astring3, (LPSTARTUPINFOA)lpStartupInfo,
1695 lpProcessInfo);
1696 if(astring3) FreeAsciiString(astring3);
1697 if(astring2) FreeAsciiString(astring2);
1698 if(astring1) FreeAsciiString(astring1);
1699 return(rc);
1700}
1701//******************************************************************************
1702//******************************************************************************
1703HINSTANCE WIN32API WinExec(LPCSTR lpCmdLine, UINT nCmdShow)
1704{
1705 STARTUPINFOA startinfo = {0};
1706 PROCESS_INFORMATION procinfo;
1707 DWORD rc;
1708
1709 dprintf(("KERNEL32: WinExec %s\n", lpCmdLine));
1710 startinfo.dwFlags = nCmdShow;
1711 if(CreateProcessA(NULL, (LPSTR)lpCmdLine, NULL, NULL, FALSE, 0, NULL, NULL,
1712 &startinfo, &procinfo) == FALSE)
1713 {
1714 return 0;
1715 }
1716 //block until the launched app waits for input (or a timeout of 15 seconds)
1717 //TODO: Shouldn't call Open32, but the api in user32..
1718 rc = O32_WaitForInputIdle(procinfo.hProcess, 15000);
1719 if(rc != 0) {
1720 dprintf(("WinExec: WaitForInputIdle %x returned %x", procinfo.hProcess, rc));
1721 }
1722 return procinfo.hProcess; //correct?
1723}
1724/**********************************************************************
1725 * LoadModule (KERNEL32.499)
1726 *
1727 * Wine: 20000909
1728 *
1729 * Copyright 1995 Alexandre Julliard
1730 */
1731HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock )
1732{
1733 LOADPARAMS *params = (LOADPARAMS *)paramBlock;
1734 PROCESS_INFORMATION info;
1735 STARTUPINFOA startup;
1736 HINSTANCE hInstance;
1737 LPSTR cmdline, p;
1738 char filename[MAX_PATH];
1739 BYTE len;
1740
1741 dprintf(("LoadModule %s %x", name, paramBlock));
1742
1743 if (!name) return ERROR_FILE_NOT_FOUND;
1744
1745 if (!SearchPathA( NULL, name, ".exe", sizeof(filename), filename, NULL ) &&
1746 !SearchPathA( NULL, name, NULL, sizeof(filename), filename, NULL ))
1747 return GetLastError();
1748
1749 len = (BYTE)params->lpCmdLine[0];
1750 if (!(cmdline = (LPSTR)HeapAlloc( GetProcessHeap(), 0, strlen(filename) + len + 2 )))
1751 return ERROR_NOT_ENOUGH_MEMORY;
1752
1753 strcpy( cmdline, filename );
1754 p = cmdline + strlen(cmdline);
1755 *p++ = ' ';
1756 memcpy( p, params->lpCmdLine + 1, len );
1757 p[len] = 0;
1758
1759 memset( &startup, 0, sizeof(startup) );
1760 startup.cb = sizeof(startup);
1761 if (params->lpCmdShow)
1762 {
1763 startup.dwFlags = STARTF_USESHOWWINDOW;
1764 startup.wShowWindow = params->lpCmdShow[1];
1765 }
1766
1767 if (CreateProcessA( filename, cmdline, NULL, NULL, FALSE, 0,
1768 params->lpEnvAddress, NULL, &startup, &info ))
1769 {
1770 /* Give 15 seconds to the app to come up */
1771 if ( O32_WaitForInputIdle ( info.hProcess, 15000 ) == 0xFFFFFFFF )
1772 dprintf(("ERROR: WaitForInputIdle failed: Error %ld\n", GetLastError() ));
1773 hInstance = 33;
1774 /* Close off the handles */
1775 CloseHandle( info.hThread );
1776 CloseHandle( info.hProcess );
1777 }
1778 else if ((hInstance = GetLastError()) >= 32)
1779 {
1780 dprintf(("ERROR: Strange error set by CreateProcess: %d\n", hInstance ));
1781 hInstance = 11;
1782 }
1783
1784 HeapFree( GetProcessHeap(), 0, cmdline );
1785 return hInstance;
1786}
1787//******************************************************************************
1788//******************************************************************************
1789FARPROC WIN32API GetProcAddress(HMODULE hModule, LPCSTR lpszProc)
1790{
1791 Win32ImageBase *winmod;
1792 FARPROC proc;
1793 ULONG ulAPIOrdinal;
1794
1795 if(hModule == 0 || hModule == -1 || (WinExe && hModule == WinExe->getInstanceHandle())) {
1796 winmod = WinExe;
1797 }
1798 else winmod = (Win32ImageBase *)Win32DllBase::findModule((HINSTANCE)hModule);
1799
1800 if(winmod) {
1801 ulAPIOrdinal = (ULONG)lpszProc;
1802 if (ulAPIOrdinal <= 0x0000FFFF) {
1803 proc = (FARPROC)winmod->getApi((int)ulAPIOrdinal);
1804 }
1805 else proc = (FARPROC)winmod->getApi((char *)lpszProc);
1806 if(proc == 0) {
1807#ifdef DEBUG
1808 if(ulAPIOrdinal <= 0x0000FFFF) {
1809 dprintf(("GetProcAddress %x %x not found!", hModule, ulAPIOrdinal));
1810 }
1811 else dprintf(("GetProcAddress %x %s not found!", hModule, lpszProc));
1812#endif
1813 SetLastError(ERROR_PROC_NOT_FOUND);
1814 }
1815 if(HIWORD(lpszProc))
1816 dprintf(("KERNEL32: GetProcAddress %s from %X returned %X\n", lpszProc, hModule, proc));
1817 else dprintf(("KERNEL32: GetProcAddress %x from %X returned %X\n", lpszProc, hModule, proc));
1818 return proc;
1819 }
1820 proc = O32_GetProcAddress(hModule, lpszProc);
1821 if(HIWORD(lpszProc))
1822 dprintf(("KERNEL32: GetProcAddress %s from %X returned %X\n", lpszProc, hModule, proc));
1823 else dprintf(("KERNEL32: GetProcAddress %x from %X returned %X\n", lpszProc, hModule, proc));
1824 return(proc);
1825}
1826//******************************************************************************
1827//Retrieve the version
1828//******************************************************************************
1829BOOL SYSTEM GetVersionStruct(char *lpszModName, char *verstruct, ULONG bufLength)
1830{
1831 Win32ImageBase *winimage;
1832 HINSTANCE hDll;
1833 BOOL rc = FALSE;
1834
1835 dprintf(("GetVersionStruct of module %s %x %d", lpszModName, verstruct, bufLength));
1836 if(verstruct == NULL) {
1837 SetLastError(ERROR_INVALID_PARAMETER);
1838 return FALSE;
1839 }
1840 if (WinExe != NULL && WinExe->matchModName(lpszModName)) {
1841 return WinExe->getVersionStruct(verstruct, bufLength);
1842 }
1843 hDll = LoadLibraryExA(lpszModName, 0, LOAD_LIBRARY_AS_DATAFILE);
1844 if(hDll == 0) {
1845 dprintf(("ERROR: GetVersionStruct: Unable to load module!!"));
1846 return 0;
1847 }
1848 winimage = (Win32ImageBase *)Win32DllBase::findModule(hDll);
1849 if(winimage != NULL) {
1850 rc = winimage->getVersionStruct(verstruct, bufLength);
1851 }
1852 else {
1853 dprintf(("GetVersionStruct; just loaded dll %s, but can't find it now!", lpszModName));
1854 DebugInt3();
1855 }
1856 FreeLibrary(hDll);
1857 return rc;
1858}
1859//******************************************************************************
1860//******************************************************************************
1861ULONG SYSTEM GetVersionSize(char *lpszModName)
1862{
1863 Win32ImageBase *winimage;
1864 HINSTANCE hDll;
1865 ULONG size = 0;
1866
1867 dprintf(("GetVersionSize of %s", lpszModName));
1868 if (WinExe != NULL && WinExe->matchModName(lpszModName)) {
1869 return WinExe->getVersionSize();
1870 }
1871
1872 hDll = LoadLibraryExA(lpszModName, 0, LOAD_LIBRARY_AS_DATAFILE);
1873 if(hDll == 0) {
1874 dprintf(("ERROR: GetVersionStruct: Unable to load module!!"));
1875 return 0;
1876 }
1877 winimage = (Win32ImageBase *)Win32DllBase::findModule(hDll);
1878 if(winimage != NULL) {
1879 size = winimage->getVersionSize();
1880 }
1881 else {
1882 dprintf(("GetVersionSize; just loaded dll %s, but can't find it now!", lpszModName));
1883 DebugInt3();
1884 }
1885 FreeLibrary(hDll);
1886 return size;
1887}
1888//******************************************************************************
1889//******************************************************************************
1890ODINFUNCTION1(BOOL,DisableThreadLibraryCalls,HMODULE,hModule)
1891{
1892 Win32DllBase *winmod;
1893 FARPROC proc;
1894 ULONG ulAPIOrdinal;
1895
1896 winmod = Win32DllBase::findModule((HINSTANCE)hModule);
1897 if(winmod)
1898 {
1899 // don't call ATTACH/DETACH thread functions in DLL
1900 winmod->disableThreadLibraryCalls();
1901 return TRUE;
1902 }
1903 else
1904 {
1905 // raise error condition
1906 SetLastError(ERROR_INVALID_HANDLE);
1907 return FALSE;
1908 }
1909}
1910//******************************************************************************
1911//******************************************************************************
Note: See TracBrowser for help on using the repository browser.