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

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

vio, thread exit fixes

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