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

Last change on this file since 9497 was 9497, checked in by sandervl, 23 years ago

bugfix

File size: 89.3 KB
Line 
1/* $Id: wprocess.cpp,v 1.165 2002-12-13 16:54:17 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#include "odin32validate.h"
35#include "exceptutil.h"
36#include "asmutil.h"
37#include "oslibdos.h"
38#include "oslibmisc.h"
39#include "oslibdebug.h"
40#include "hmcomm.h"
41
42#include "console.h"
43#include "wincon.h"
44#include "cio.h"
45#include "versionos2.h" /*PLF Wed 98-03-18 02:36:51*/
46#include <wprocess.h>
47#include "mmap.h"
48#include "initterm.h"
49#include "directory.h"
50
51#define DBG_LOCALLOG DBG_wprocess
52#include "dbglocal.h"
53
54#ifdef PROFILE
55#include <perfview.h>
56#include <profiler.h>
57#endif /* PROFILE */
58
59
60ODINDEBUGCHANNEL(KERNEL32-WPROCESS)
61
62
63/*******************************************************************************
64* Global Variables *
65*******************************************************************************/
66BOOL fIsOS2Image = FALSE; /* TRUE -> Odin32 OS/2 application (not converted!) */
67 /* FALSE -> otherwise */
68BOOL fExitProcess = FALSE;
69
70//Commandlines
71PCSTR pszCmdLineA; /* ASCII/ANSII commandline. */
72PCWSTR pszCmdLineW; /* Unicode commandline. */
73
74//Process database
75PDB ProcessPDB = {0};
76ENVDB ProcessENVDB = {0};
77CONCTRLDATA ProcessConCtrlData = {0};
78STARTUPINFOA StartupInfo = {0};
79CHAR unknownPDBData[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 ,0 ,0};
80USHORT ProcessTIBSel = 0;
81DWORD *TIBFlatPtr = 0;
82
83//list of thread database structures
84static TEB *threadList = 0;
85static VMutex threadListMutex;
86
87//TODO: This should not be here: (need to rearrange NTDLL; kernel32 can't depend on ntdll)
88BOOLEAN (* WINAPI RtlAllocateAndInitializeSid) ( PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
89 BYTE nSubAuthorityCount,
90 DWORD nSubAuthority0,
91 DWORD nSubAuthority1,
92 DWORD nSubAuthority2,
93 DWORD nSubAuthority3,
94 DWORD nSubAuthority4,
95 DWORD nSubAuthority5,
96 DWORD nSubAuthority6,
97 DWORD nSubAuthority7,
98 PSID *pSid);
99static HINSTANCE hInstNTDll = 0;
100
101//******************************************************************************
102//******************************************************************************
103TEB *WIN32API GetThreadTEB()
104{
105 if(TIBFlatPtr == NULL) {
106 return 0;
107 }
108 return (TEB *)*TIBFlatPtr;
109}
110//******************************************************************************
111//******************************************************************************
112TEB *WIN32API GetTEBFromThreadId(ULONG threadId)
113{
114 TEB *teb = threadList;
115
116 threadListMutex.enter();
117 while(teb) {
118 if(teb->o.odin.threadId == threadId) {
119 break;
120 }
121 teb = teb->o.odin.next;
122 }
123 threadListMutex.leave();
124 return teb;
125}
126//******************************************************************************
127//******************************************************************************
128TEB *WIN32API GetTEBFromThreadHandle(HANDLE hThread)
129{
130 TEB *teb = threadList;
131
132 threadListMutex.enter();
133 while(teb) {
134 if(teb->o.odin.hThread == hThread) {
135 break;
136 }
137 teb = teb->o.odin.next;
138 }
139 threadListMutex.leave();
140 return teb;
141}
142//******************************************************************************
143//Allocate TEB structure for new thread
144//******************************************************************************
145TEB *WIN32API CreateTEB(HANDLE hThread, DWORD dwThreadId)
146{
147 USHORT tibsel;
148 TEB *winteb;
149
150 if(OSLibAllocSel(sizeof(TEB), &tibsel) == FALSE)
151 {
152 dprintf(("InitializeTIB: selector alloc failed!!"));
153 DebugInt3();
154 return NULL;
155 }
156 winteb = (TEB *)OSLibSelToFlat(tibsel);
157 if(winteb == NULL)
158 {
159 dprintf(("InitializeTIB: DosSelToFlat failed!!"));
160 DebugInt3();
161 return NULL;
162 }
163 memset(winteb, 0, sizeof(TEB));
164
165 threadListMutex.enter();
166 TEB *teblast = threadList;
167 if(!teblast) {
168 threadList = winteb;
169 winteb->o.odin.next = NULL;
170 }
171 else {
172 while(teblast->o.odin.next) {
173 teblast = teblast->o.odin.next;
174 }
175 teblast->o.odin.next = winteb;
176 }
177 threadListMutex.leave();
178
179 winteb->except = (PVOID)-1; /* 00 Head of exception handling chain */
180 winteb->htask16 = (USHORT)OSLibGetPIB(PIB_TASKHNDL); /* 0c Win16 task handle */
181 winteb->stack_sel = getSS(); /* 0e 16-bit stack selector */
182 winteb->self = winteb; /* 18 Pointer to this structure */
183 winteb->flags = TEBF_WIN32; /* 1c Flags */
184 winteb->queue = 0; /* 28 Message queue */
185 winteb->tls_ptr = &winteb->tls_array[0]; /* 2c Pointer to TLS array */
186 winteb->process = &ProcessPDB; /* 30 owning process (used by NT3.51 applets)*/
187 winteb->delta_priority = THREAD_PRIORITY_NORMAL;
188 winteb->process = &ProcessPDB;
189
190 //store selector of new TEB
191 winteb->teb_sel = tibsel;
192
193 winteb->o.odin.hThread = hThread;
194 winteb->o.odin.threadId = dwThreadId;
195
196 // Event semaphore (auto-reset) to signal message post to MsgWaitForMultipleObjects
197 winteb->o.odin.hPostMsgEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
198
199 return winteb;
200}
201//******************************************************************************
202// Set up the TIB selector and memory for the main thread
203//******************************************************************************
204TEB *WIN32API InitializeMainThread()
205{
206 HANDLE hThreadMain;
207 TEB *teb;
208
209 //Allocate one dword to store the flat address of our TEB
210 dprintf(("InitializeMainThread Process handle %x, id %x", GetCurrentProcess(), GetCurrentProcessId()));
211
212 TIBFlatPtr = (DWORD *)OSLibAllocThreadLocalMemory(1);
213 if(TIBFlatPtr == 0) {
214 dprintf(("InitializeTIB: local thread memory alloc failed!!"));
215 DebugInt3();
216 return NULL;
217 }
218 //SvL: This doesn't really create a thread, but only sets up the
219 // handle of thread 0
220 hThreadMain = HMCreateThread(NULL, 0, 0, 0, 0, 0, TRUE);
221
222 //create and initialize TEB
223 teb = CreateTEB(hThreadMain, GetCurrentThreadId());
224 if(teb == NULL || InitializeThread(teb, TRUE) == FALSE) {
225 DebugInt3();
226 return NULL;
227 }
228
229 ProcessTIBSel = teb->teb_sel;
230
231 //todo initialize PDB during process creation
232 //todo: initialize TLS array if required
233 //TLS in executable always TLS index 0?
234//// ProcessPDB.exit_code = 0x103; /* STILL_ACTIVE */
235 ProcessPDB.threads = 1;
236 ProcessPDB.running_threads = 1;
237 ProcessPDB.ring0_threads = 1;
238 ProcessPDB.system_heap = GetProcessHeap();
239 ProcessPDB.parent = 0;
240 ProcessPDB.group = &ProcessPDB;
241 ProcessPDB.priority = 8; /* Normal */
242 ProcessPDB.heap = ProcessPDB.system_heap; /* will be changed later on */
243 ProcessPDB.next = NULL;
244 ProcessPDB.winver = 0xffff; /* to be determined */
245 ProcessPDB.server_pid = (void *)GetCurrentProcessId();
246 ProcessPDB.tls_bits[0] = 0; //all tls slots are free
247 ProcessPDB.tls_bits[1] = 0;
248
249 GetSystemTime(&ProcessPDB.creationTime);
250
251 /* Initialize the critical section */
252 InitializeCriticalSection(&ProcessPDB.crit_section );
253
254 //initialize the environment db entry.
255 ProcessPDB.env_db = &ProcessENVDB;
256 ProcessENVDB.startup_info = &StartupInfo;
257 ProcessENVDB.environ = GetEnvironmentStringsA();
258 ProcessENVDB.cmd_line = (CHAR*)(void*)pszCmdLineA;
259 ProcessENVDB.cmd_lineW = (WCHAR*)(void*)pszCmdLineW;
260 ProcessENVDB.break_handlers = &ProcessConCtrlData;
261 ProcessConCtrlData.fIgnoreCtrlC = FALSE; /* TODO! Should be inherited from parent. */
262 ProcessConCtrlData.pHead = ProcessConCtrlData.pTail = (PCONCTRL)malloc(sizeof(CONCTRL));
263 ProcessConCtrlData.pHead->pfnHandler = (void*)DefaultConsoleCtrlHandler;
264 ProcessConCtrlData.pHead->pNext = ProcessConCtrlData.pHead->pPrev = NULL;
265 ProcessConCtrlData.pHead->flFlags = ODIN32_CONCTRL_FLAGS_INIT;
266 InitializeCriticalSection(&ProcessENVDB.section);
267
268// ProcessPDB.startup_info = &StartupInfo;
269 ProcessPDB.unknown10 = (PVOID)&unknownPDBData[0];
270 StartupInfo.cb = sizeof(StartupInfo);
271 ProcessENVDB.hStdin = StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
272 ProcessENVDB.hStdout = StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
273 ProcessENVDB.hStderr = StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
274
275 return teb;
276}
277//******************************************************************************
278// Set up the TEB structure of the CURRENT (!) thread
279//******************************************************************************
280BOOL WIN32API InitializeThread(TEB *winteb, BOOL fMainThread)
281{
282 //store TEB address in thread locale memory for easy retrieval
283 *TIBFlatPtr = (DWORD)winteb;
284
285//// winteb->exit_code = 0x103; /* STILL_ACTIVE */
286
287 winteb->stack_top = (PVOID)OSLibGetTIB(TIB_STACKTOP); /* 04 Top of thread stack */
288 winteb->stack_top = (PVOID)(((ULONG)winteb->stack_top + 0xFFF) & ~0xFFF);
289 //round to next page (OS/2 doesn't return a nice rounded value)
290 winteb->stack_low = (PVOID)OSLibGetTIB(TIB_STACKLOW); /* 08 Stack low-water mark */
291 //round to page boundary (OS/2 doesn't return a nice rounded value)
292 winteb->stack_low = (PVOID)((ULONG)winteb->stack_low & ~0xFFF);
293
294 winteb->o.odin.OrgTIBSel = GetFS();
295 winteb->o.odin.pWsockData = NULL;
296#ifdef DEBUG
297 winteb->o.odin.dbgCallDepth = 0;
298#endif
299 winteb->o.odin.pMessageBuffer = NULL;
300 winteb->o.odin.lcid = GetUserDefaultLCID();
301
302 if(OSLibGetPIB(PIB_TASKTYPE) == TASKTYPE_PM)
303 {
304 winteb->flags = 0; //todo gui
305 }
306 else winteb->flags = 0; //todo textmode
307
308 //Initialize thread security objects (TODO: Not complete)
309 if(hInstNTDll == 0) {
310 hInstNTDll = LoadLibraryA("NTDLL.DLL");
311 *(ULONG *)&RtlAllocateAndInitializeSid = (ULONG)GetProcAddress(hInstNTDll, "RtlAllocateAndInitializeSid");
312 if(RtlAllocateAndInitializeSid == NULL) {
313 DebugInt3();
314 }
315 }
316 SID_IDENTIFIER_AUTHORITY sidIdAuth = {0};
317 winteb->o.odin.threadinfo.dwType = SECTYPE_PROCESS | SECTYPE_INITIALIZED;
318
319 if (NULL != RtlAllocateAndInitializeSid) {
320 RtlAllocateAndInitializeSid(&sidIdAuth, 1, 0, 0, 0, 0, 0, 0, 0, 0, &winteb->o.odin.threadinfo.SidUser.User.Sid);
321 }
322 else DebugInt3();
323
324 winteb->o.odin.threadinfo.SidUser.User.Attributes = 0; //?????????
325
326 winteb->o.odin.threadinfo.pTokenGroups = (TOKEN_GROUPS*)malloc(sizeof(TOKEN_GROUPS));
327 winteb->o.odin.threadinfo.pTokenGroups->GroupCount = 1;
328
329 if (NULL != RtlAllocateAndInitializeSid) {
330 RtlAllocateAndInitializeSid(&sidIdAuth, 1, 0, 0, 0, 0, 0, 0, 0, 0, &winteb->o.odin.threadinfo.PrimaryGroup.PrimaryGroup);
331 }
332 else DebugInt3();
333
334 winteb->o.odin.threadinfo.pTokenGroups->Groups[0].Sid = winteb->o.odin.threadinfo.PrimaryGroup.PrimaryGroup;
335 winteb->o.odin.threadinfo.pTokenGroups->Groups[0].Attributes = 0; //????
336// pPrivilegeSet = NULL;
337// pTokenPrivileges= NULL;
338// TokenOwner = {0};
339// DefaultDACL = {0};
340// TokenSource = {0};
341 winteb->o.odin.threadinfo.TokenType = TokenPrimary;
342
343 dprintf(("InitializeTIB setup TEB with selector %x", winteb->teb_sel));
344 dprintf(("InitializeTIB: FS(%x):[0] = %x", GetFS(), QueryExceptionChain()));
345 return TRUE;
346}
347//******************************************************************************
348// Destroy the TIB selector and memory for the current thread
349//******************************************************************************
350void WIN32API DestroyTEB(TEB *winteb)
351{
352 SHORT orgtibsel;
353
354 dprintf(("DestroyTIB: FS = %x", GetFS()));
355 dprintf(("DestroyTIB: FS:[0] = %x", QueryExceptionChain()));
356
357 orgtibsel = winteb->o.odin.OrgTIBSel;
358
359 dprintf(("DestroyTIB: OSLibFreeSel %x", winteb->teb_sel));
360
361 threadListMutex.enter();
362 TEB *curteb = threadList;
363 if(curteb == winteb) {
364 threadList = winteb->o.odin.next;
365 }
366 else {
367 while(curteb->o.odin.next != winteb) {
368 curteb = curteb->o.odin.next;
369 if(curteb == NULL) {
370 dprintf(("DestroyTIB: couldn't find teb %x", winteb));
371 DebugInt3();
372 break;
373 }
374 }
375 if(curteb) {
376 curteb->o.odin.next = winteb->o.odin.next;
377 }
378 }
379 threadListMutex.leave();
380
381 // free allocated memory for security structures
382 free( winteb->o.odin.threadinfo.pTokenGroups );
383
384 // free PostMessage event semaphore
385 if(winteb->o.odin.hPostMsgEvent) {
386 CloseHandle(winteb->o.odin.hPostMsgEvent);
387 }
388
389#ifdef DEBUG
390 if (winteb->o.odin.arrstrCallStack != NULL)
391 free( winteb->o.odin.arrstrCallStack );
392#endif
393
394 //Restore our original FS selector
395 SetFS(orgtibsel);
396
397 //And free our own
398 OSLibFreeSel(winteb->teb_sel);
399
400 *TIBFlatPtr = 0;
401
402 dprintf(("DestroyTIB: FS(%x):[0] = %x", GetFS(), QueryExceptionChain()));
403 return;
404}
405//******************************************************************************
406//******************************************************************************
407ULONG WIN32API GetProcessTIBSel()
408{
409 if(fExitProcess) {
410 return 0;
411 }
412 return ProcessTIBSel;
413}
414/******************************************************************************/
415/******************************************************************************/
416void SetPDBInstance(HINSTANCE hInstance)
417{
418 ProcessPDB.hInstance = hInstance;
419}
420/******************************************************************************/
421/******************************************************************************/
422void WIN32API RestoreOS2TIB()
423{
424 SHORT orgtibsel;
425 TEB *winteb;
426
427 //If we're running an Odin32 OS/2 application (not converted!), then we
428 //we don't switch FS selectors
429 if(fIsOS2Image) {
430 return;
431 }
432
433 winteb = (TEB *)*TIBFlatPtr;
434 if(winteb) {
435 orgtibsel = winteb->o.odin.OrgTIBSel;
436
437 //Restore our original FS selector
438 SetFS(orgtibsel);
439 }
440}
441/******************************************************************************/
442//Switch to WIN32 TIB (FS selector)
443//NOTE: This is not done for Odin32 applications (LX), unless
444// fForceSwitch is TRUE)
445/******************************************************************************/
446USHORT WIN32API SetWin32TIB(BOOL fForceSwitch)
447{
448 SHORT win32tibsel;
449 TEB *winteb;
450
451 //If we're running an Odin32 OS/2 application (not converted!), then we
452 //we don't switch FS selectors
453 if(fIsOS2Image && !fForceSwitch) {
454 return GetFS();
455 }
456
457 winteb = (TEB *)*TIBFlatPtr;
458 if(winteb) {
459 win32tibsel = winteb->teb_sel;
460
461 //Restore our win32 FS selector
462 return SetReturnFS(win32tibsel);
463 }
464 else {
465 return GetFS();
466 }
467 // nested calls are OK, OS2ToWinCallback for instance
468 //else DebugInt3();
469
470 return GetFS();
471}
472//******************************************************************************
473//******************************************************************************
474//#define DEBUG_HEAPSTATE
475#ifdef DEBUG_HEAPSTATE
476char *pszHeapDump = NULL;
477char *pszHeapDumpStart = NULL;
478
479int _LNK_CONV callback_function(const void *pentry, size_t sz, int useflag, int status,
480 const char *filename, size_t line)
481{
482 if (_HEAPOK != status) {
483// dprintf(("status is not _HEAPOK."));
484 return 1;
485 }
486 if (_USEDENTRY == useflag && sz && filename && line && pszHeapDump) {
487 sprintf(pszHeapDump, "allocated %08x %u at %s %d\n", pentry, sz, filename, line);
488 pszHeapDump += strlen(pszHeapDump);
489 }
490
491 return 0;
492}
493//******************************************************************************
494//******************************************************************************
495#endif
496VOID WIN32API ExitProcess(DWORD exitcode)
497{
498 HANDLE hThread = GetCurrentThread();
499 TEB *teb;
500
501 dprintf(("KERNEL32: ExitProcess %d\n", exitcode));
502 dprintf(("KERNEL32: ExitProcess FS = %x\n", GetFS()));
503
504 fExitProcess = TRUE;
505
506 SetOS2ExceptionChain(-1);
507
508 HMDeviceCommClass::CloseOverlappedIOHandlers();
509
510 //detach all dlls (LIFO order) before really unloading them; this
511 //should take care of circular dependencies (crash while accessing
512 //memory of a dll that has just been freed)
513 dprintf(("********************************************"));
514 dprintf(("**** Detach process from all dlls -- START"));
515 Win32DllBase::detachProcessFromAllDlls();
516 dprintf(("**** Detach process from all dlls -- END"));
517 dprintf(("********************************************"));
518
519 if(WinExe) {
520 delete(WinExe);
521 WinExe = NULL;
522 }
523
524 //Note: Needs to be done after deleting WinExe (destruction of exe + dll objects)
525 //Flush and delete all open memory mapped files
526 Win32MemMap::deleteAll();
527
528 //SvL: We must make sure no threads are still suspended (with SuspendThread)
529 // OS/2 seems to be unable to terminate the process otherwise (exitlist hang)
530 threadListMutex.enter();
531 teb = threadList;
532 while(teb) {
533 if(teb->o.odin.hThread != hThread && teb->o.odin.dwSuspend > 0) {
534 //kill any threads that are suspended; dangerous, but so is calling
535 //SuspendThread; we assume the app knew what it was doing
536 TerminateThread(teb->o.odin.hThread, 0);
537 ResumeThread(teb->o.odin.hThread);
538 }
539 teb = teb->o.odin.next;
540 }
541 threadListMutex.leave();
542
543#ifdef DEBUG_HEAPSTATE
544 pszHeapDumpStart = pszHeapDump = (char *)malloc(10*1024*1024);
545 _heap_walk(callback_function);
546 dprintf((pszHeapDumpStart));
547 free(pszHeapDumpStart);
548#endif
549
550#ifdef PROFILE
551 // Note: after this point we do not expect any more Win32-API calls,
552 // so this is probably the best time to dump the gathered profiling
553 // information
554 PerfView_Write();
555 ProfilerWrite();
556 ProfilerTerminate();
557#endif /* PROFILE */
558
559 //Restore original OS/2 TIB selector
560 teb = GetThreadTEB();
561 if(teb) DestroyTEB(teb);
562 SetExceptionChain((ULONG)-1);
563
564 //avoid crashes since win32 & OS/2 exception handler aren't identical
565 //(terminate process generates two exceptions)
566 /* @@@PH 1998/02/12 Added Console Support */
567 if (iConsoleIsActive())
568 iConsoleWaitClose();
569
570 O32_ExitProcess(exitcode);
571}
572//******************************************************************************
573//******************************************************************************
574BOOL WIN32API FreeLibrary(HINSTANCE hinstance)
575{
576 Win32DllBase *winmod;
577 BOOL rc;
578
579 SetLastError(ERROR_SUCCESS);
580 //SvL: Ignore FreeLibary for executable
581 if(WinExe && hinstance == WinExe->getInstanceHandle()) {
582 return TRUE;
583 }
584
585 winmod = Win32DllBase::findModule(hinstance);
586 if(winmod) {
587 dprintf(("FreeLibrary %s", winmod->getName()));
588 //Only free it when the nrDynamicLibRef != 0
589 //This prevent problems after ExitProcess:
590 //i.e. dll A is referenced by our exe and loaded with LoadLibrary by dll B
591 // During ExitProcess it's unloaded once (before dll B), dll B calls
592 // FreeLibrary, but our exe also has a reference -> unloaded too many times
593 if(winmod->isDynamicLib()) {
594 winmod->decDynamicLib();
595 winmod->Release();
596 }
597 else {
598 dprintf(("Skipping dynamic unload as nrDynamicLibRef == 0"));
599 }
600 return(TRUE);
601 }
602 dprintf(("WARNING: KERNEL32: FreeLibrary %s %x NOT FOUND!", OSLibGetDllName(hinstance), hinstance));
603 return(TRUE);
604}
605/*****************************************************************************
606 * Name : VOID WIN32API FreeLibraryAndExitThread
607 * Purpose : The FreeLibraryAndExitThread function decrements the reference
608 * count of a loaded dynamic-link library (DLL) by one, and then
609 * calls ExitThread to terminate the calling thread.
610 * The function does not return.
611 *
612 * The FreeLibraryAndExitThread function gives threads that are
613 * created and executed within a dynamic-link library an opportunity
614 * to safely unload the DLL and terminate themselves.
615 * Parameters:
616 * Variables :
617 * Result :
618 * Remark :
619 *****************************************************************************/
620VOID WIN32API FreeLibraryAndExitThread( HMODULE hLibModule, DWORD dwExitCode)
621{
622
623 dprintf(("KERNEL32: FreeLibraryAndExitThread(%08x,%08x)", hLibModule, dwExitCode));
624 FreeLibrary(hLibModule);
625 ExitThread(dwExitCode);
626}
627/******************************************************************************/
628/******************************************************************************/
629/**
630 * LoadLibraryA can be used to map a DLL module into the calling process's
631 * addressspace. It returns a handle that can be used with GetProcAddress to
632 * get addresses of exported entry points (functions and variables).
633 *
634 * LoadLibraryA can also be used to map executable (.exe) modules into the
635 * address to access resources in the module. However, LoadLibrary can't be
636 * used to run an executable (.exe) module.
637 *
638 * @returns Handle to the library which was loaded.
639 * @param lpszLibFile Pointer to zero ASCII string giving the name of the
640 * executable image (either a Dll or an Exe) which is to be
641 * loaded.
642 *
643 * If no extention is specified the default .DLL extention is
644 * appended to the name. End the filename with an '.' if the
645 * file does not have an extention (and don't want the .DLL
646 * appended).
647 *
648 * If no path is specified, this API will use the Odin32
649 * standard search strategy to find the file. This strategy
650 * is described in the method Win32ImageBase::findDLL.
651 *
652 * This API likes to have backslashes (\), but will probably
653 * accept forward slashes too. Win32 SDK docs says that it
654 * should not contain forward slashes.
655 *
656 * Win32 SDK docs adds:
657 * "The name specified is the file name of the module and
658 * is not related to the name stored in the library module
659 * itself, as specified by the LIBRARY keyword in the
660 * module-definition (.def) file."
661 *
662 * @sketch Call LoadLibraryExA with flags set to 0.
663 * @status Odin32 Completely Implemented.
664 * @author Sander van Leeuwen (sandervl@xs4all.nl)
665 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
666 * @remark Forwards to LoadLibraryExA.
667 */
668HINSTANCE WIN32API LoadLibraryA(LPCTSTR lpszLibFile)
669{
670 HINSTANCE hDll;
671
672 dprintf(("KERNEL32: LoadLibraryA(%s) --> LoadLibraryExA(lpszLibFile, 0, 0)",
673 lpszLibFile));
674 hDll = LoadLibraryExA(lpszLibFile, 0, 0);
675 dprintf(("KERNEL32: LoadLibraryA(%s) returns 0x%x",
676 lpszLibFile, hDll));
677 return hDll;
678}
679
680
681/**
682 * LoadLibraryW can be used to map a DLL module into the calling process's
683 * addressspace. It returns a handle that can be used with GetProcAddress to
684 * get addresses of exported entry points (functions and variables).
685 *
686 * LoadLibraryW can also be used to map executable (.exe) modules into the
687 * address to access resources in the module. However, LoadLibrary can't be
688 * used to run an executable (.exe) module.
689 *
690 * @returns Handle to the library which was loaded.
691 * @param lpszLibFile Pointer to Unicode string giving the name of
692 * the executable image (either a Dll or an Exe) which is to
693 * be loaded.
694 *
695 * If no extention is specified the default .DLL extention is
696 * appended to the name. End the filename with an '.' if the
697 * file does not have an extention (and don't want the .DLL
698 * appended).
699 *
700 * If no path is specified, this API will use the Odin32
701 * standard search strategy to find the file. This strategy
702 * is described in the method Win32ImageBase::findDLL.
703 *
704 * This API likes to have backslashes (\), but will probably
705 * accept forward slashes too. Win32 SDK docs says that it
706 * should not contain forward slashes.
707 *
708 * Win32 SDK docs adds:
709 * "The name specified is the file name of the module and
710 * is not related to the name stored in the library module
711 * itself, as specified by the LIBRARY keyword in the
712 * module-definition (.def) file."
713 *
714 * @sketch Convert Unicode name to ascii.
715 * Call LoadLibraryExA with flags set to 0.
716 * free ascii string.
717 * @status Odin32 Completely Implemented.
718 * @author Sander van Leeuwen (sandervl@xs4all.nl)
719 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
720 * @remark Forwards to LoadLibraryExA.
721 */
722HINSTANCE WIN32API LoadLibraryW(LPCWSTR lpszLibFile)
723{
724 char * pszAsciiLibFile;
725 HINSTANCE hDll;
726
727 pszAsciiLibFile = UnicodeToAsciiString(lpszLibFile);
728 dprintf(("KERNEL32: LoadLibraryW(%s) --> LoadLibraryExA(lpszLibFile, 0, 0)",
729 pszAsciiLibFile));
730 hDll = LoadLibraryExA(pszAsciiLibFile, NULL, 0);
731 dprintf(("KERNEL32: LoadLibraryW(%s) returns 0x%x",
732 pszAsciiLibFile, hDll));
733 FreeAsciiString(pszAsciiLibFile);
734
735 return hDll;
736}
737
738//******************************************************************************
739//Custom build function to disable loading of LX dlls
740static BOOL fDisableLXDllLoading = FALSE;
741//******************************************************************************
742void WIN32API ODIN_DisableLXDllLoading()
743{
744 fDisableLXDllLoading = TRUE;
745}
746
747/**
748 * LoadLibraryExA can be used to map a DLL module into the calling process's
749 * addressspace. It returns a handle that can be used with GetProcAddress to
750 * get addresses of exported entry points (functions and variables).
751 *
752 * LoadLibraryExA can also be used to map executable (.exe) modules into the
753 * address to access resources in the module. However, LoadLibrary can't be
754 * used to run an executable (.exe) module.
755 *
756 * @returns Handle to the library which was loaded.
757 * @param lpszLibFile Pointer to Unicode string giving the name of
758 * the executable image (either a Dll or an Exe) which is to
759 * be loaded.
760 *
761 * If no extention is specified the default .DLL extention is
762 * appended to the name. End the filename with an '.' if the
763 * file does not have an extention (and don't want the .DLL
764 * appended).
765 *
766 * If no path is specified, this API will use the Odin32
767 * standard search strategy to find the file. This strategy
768 * is described in the method Win32ImageBase::findDLL.
769 * This may be alterned by the LOAD_WITH_ALTERED_SEARCH_PATH
770 * flag, see below.
771 *
772 * This API likes to have backslashes (\), but will probably
773 * accept forward slashes too. Win32 SDK docs says that it
774 * should not contain forward slashes.
775 *
776 * Win32 SDK docs adds:
777 * "The name specified is the file name of the module and
778 * is not related to the name stored in the library module
779 * itself, as specified by the LIBRARY keyword in the
780 * module-definition (.def) file."
781 *
782 * @param hFile Reserved. Must be 0.
783 *
784 * @param dwFlags Flags which specifies the taken when loading the module.
785 * The value 0 makes it identical to LoadLibraryA/W.
786 *
787 * Flags:
788 *
789 * DONT_RESOLVE_DLL_REFERENCES
790 * (WinNT/2K feature): Don't load imported modules and
791 * hence don't resolve imported symbols.
792 * DllMain isn't called either. (Which is obvious since
793 * it may use one of the importe symbols.)
794 *
795 * On the other hand, if this flag is NOT set, the system
796 * load imported modules, resolves imported symbols, calls
797 * DllMain for process and thread init and term (if wished
798 * by the module).
799 *
800 *
801 * LOAD_LIBRARY_AS_DATAFILE
802 * If this flag is set, the module is mapped into the
803 * address space but is not prepared for execution. Though
804 * it's preparted for resource API. Hence, you'll use this
805 * flag when you want to load a DLL for extracting
806 * messages or resources from it.
807 *
808 * The resulting handle can be used with any Odin32 API
809 * which operates on resources.
810 * (WinNt/2k supports all resource APIs while Win9x don't
811 * support the specialized resource APIs: LoadBitmap,
812 * LoadCursor, LoadIcon, LoadImage, LoadMenu.)
813 *
814 *
815 * LOAD_WITH_ALTERED_SEARCH_PATH
816 * If this flag is set and lpszLibFile specifies a path
817 * we'll use an alternative file search strategy to find
818 * imported modules. This stratgy is simply to use the
819 * path of the module being loaded instead of the path
820 * of the executable module as the first location
821 * to search for imported modules.
822 *
823 * If this flag is clear, the standard Odin32 standard
824 * search strategy. See Win32ImageBase::findDll for
825 * further information.
826 *
827 * not implemented yet.
828 *
829 * @status Open32 Partially Implemented.
830 * @author Sander van Leeuwen (sandervl@xs4all.nl)
831 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
832 * @remark Forwards to LoadLibraryExA.
833 */
834HINSTANCE WIN32API LoadLibraryExA(LPCTSTR lpszLibFile, HANDLE hFile, DWORD dwFlags)
835{
836 HINSTANCE hDll;
837 Win32DllBase * pModule;
838 char szModname[CCHMAXPATH];
839 BOOL fPath; /* Flags which is set if the */
840 /* lpszLibFile contains a path. */
841 ULONG fPE; /* isPEImage return value. */
842 DWORD Characteristics; //file header's Characteristics
843 char *dot;
844
845 /** @sketch
846 * Some parameter validations is probably useful.
847 */
848 if (!VALID_PSZ(lpszLibFile))
849 {
850 dprintf(("KERNEL32: LoadLibraryExA(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
851 lpszLibFile, hFile, dwFlags, lpszLibFile));
852 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
853 return NULL;
854 }
855 if (!VALID_PSZMAXSIZE(lpszLibFile, CCHMAXPATH))
856 {
857 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): lpszLibFile string too long, %d\n",
858 lpszLibFile, hFile, dwFlags, strlen(lpszLibFile)));
859 SetLastError(ERROR_INVALID_PARAMETER);
860 return NULL;
861 }
862 if ((dwFlags & ~(DONT_RESOLVE_DLL_REFERENCES | LOAD_WITH_ALTERED_SEARCH_PATH | LOAD_LIBRARY_AS_DATAFILE)) != 0)
863 {
864 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): dwFlags have invalid or unsupported flags\n",
865 lpszLibFile, hFile, dwFlags));
866 SetLastError(ERROR_INVALID_PARAMETER);
867 return NULL;
868 }
869
870 /** @sketch
871 * First we'll see if the module is allready loaded - either as the EXE or as DLL.
872 * IF Executable present AND libfile matches the modname of the executable THEN
873 * RETURN instance handle of executable.
874 * Endif
875 * IF allready loaded THEN
876 * IF it's a LX dll which isn't loaded and we're using the PeLoader THEN
877 * Set Load library.
878 * Endif
879 * Inc dynamic reference count.
880 * Inc reference count.
881 * RETURN instance handle.
882 * Endif
883 */
884 strcpy(szModname, lpszLibFile);
885 strupr(szModname);
886 dot = strchr(szModname, '.');
887 if(dot == NULL) {
888 //if there's no extension or trainling dot, we
889 //assume it's a dll (see Win32 SDK docs)
890 strcat(szModname, DLL_EXTENSION);
891 }
892 else {
893 if(dot[1] == 0) {
894 //a trailing dot means the module has no extension (SDK docs)
895 *dot = 0;
896 }
897 }
898 if (WinExe != NULL && WinExe->matchModName(szModname))
899 return WinExe->getInstanceHandle();
900
901 pModule = Win32DllBase::findModule((LPSTR)szModname);
902 if (pModule)
903 {
904 pModule->incDynamicLib();
905 pModule->AddRef();
906 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Dll found %s",
907 szModname, hFile, dwFlags, pModule->getInstanceHandle(), pModule->getFullPath()));
908 return pModule->getInstanceHandle();
909 }
910
911
912 /** @sketch
913 * Test if lpszLibFile has a path or not.
914 * Copy the lpszLibFile to szModname, rename the dll and uppercase the name.
915 * IF it hasn't a path THEN
916 * Issue a findDll to find the dll/executable to be loaded.
917 * IF the Dll isn't found THEN
918 * Set last error and RETURN.
919 * Endif.
920 * Endif
921 */
922 fPath = strchr(szModname, '\\') || strchr(szModname, '/');
923 Win32DllBase::renameDll(szModname);
924
925 if (!fPath)
926 {
927 char szModName2[CCHMAXPATH];
928 strcpy(szModName2, szModname);
929 if (!Win32ImageBase::findDll(szModName2, szModname, sizeof(szModname)))
930 {
931 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): module wasn't found. returns NULL",
932 lpszLibFile, hFile, dwFlags));
933 SetLastError(ERROR_FILE_NOT_FOUND);
934 return NULL;
935 }
936 }
937
938 //test if dll is in PE or LX format
939 fPE = Win32ImageBase::isPEImage(szModname, &Characteristics, NULL);
940
941 /** @sketch
942 * IF (fDisableLXDllLoading && (!fPeLoader || fPE == failure)) THEN
943 * Try load the executable using LoadLibrary
944 * IF successfully loaded THEN
945 * IF LX dll and is using the PE Loader THEN
946 * Set Load library.
947 * Inc reference count.
948 * Endif
949 * Inc dynamic reference count.
950 * RETURN successfully.
951 * Endif
952 * Endif
953 */
954 //only call OS/2 if LX binary or win32k process
955 if (!fDisableLXDllLoading && (!fPeLoader || fPE != ERROR_SUCCESS))
956 {
957 hDll = OSLibDosLoadModule(szModname);
958 if (hDll)
959 {
960 /* OS/2 dll, system dll, converted dll or win32k took care of it. */
961 pModule = Win32DllBase::findModuleByOS2Handle(hDll);
962 if (pModule)
963 {
964 if (pModule->isLxDll())
965 {
966 ((Win32LxDll *)pModule)->setDllHandleOS2(hDll);
967 if (fPeLoader && pModule->AddRef() == -1)
968 { //-1 -> load failed (attachProcess)
969 delete pModule;
970 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
971 dprintf(("Dll %s refused to be loaded; aborting", szModname));
972 return 0;
973 }
974
975 }
976 pModule->incDynamicLib();
977 }
978 else if (fExeStarted && !fIsOS2Image) {
979 OSLibDosFreeModule(hDll);
980 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
981 dprintf(("Dll %s is not an Odin dll; unload & return failure", szModname));
982 return 0;
983 }
984 else {
985 /* bird 2001-07-10:
986 * let's fail right away instead of hitting DebugInt3s and fail other places.
987 * This is very annoying when running Opera on a debug build with netscape/2
988 * plugins present. We'll make this conditional for the time being.
989 */
990 static BOOL fFailIfUnregisteredLX = -1;
991 if (fFailIfUnregisteredLX == -1)
992 fFailIfUnregisteredLX = getenv("ODIN32.FAIL_IF_UNREGISTEREDLX") != NULL;
993 if (fExeStarted && fFailIfUnregisteredLX)
994 {
995 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Loaded OS/2 dll %s using DosLoadModule. returns NULL.",
996 lpszLibFile, hFile, dwFlags, hDll, szModname));
997 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
998 return NULL;
999 }
1000 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Loaded OS/2 dll %s using DosLoadModule.",
1001 lpszLibFile, hFile, dwFlags, hDll, szModname));
1002 return hDll; //happens when LoadLibrary is called in kernel32's initterm (nor harmful)
1003 }
1004 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Loaded %s using DosLoadModule.",
1005 lpszLibFile, hFile, dwFlags, hDll, szModname));
1006 return pModule->getInstanceHandle();
1007 }
1008 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): DosLoadModule (%s) failed. LastError=%d",
1009 lpszLibFile, hFile, dwFlags, szModname, GetLastError()));
1010 }
1011 else
1012 hDll = NULL;
1013
1014
1015 /** @sketch
1016 * If PE image THEN
1017 * IF LOAD_LIBRARY_AS_DATAFILE or Executable THEN
1018 *
1019 *
1020 * Try load the file using the Win32PeLdrDll class.
1021 * <sketch continued further down>
1022 * Else
1023 * Set last error.
1024 * (hDll is NULL)
1025 * Endif
1026 * return hDll.
1027 */
1028 if(fPE == ERROR_SUCCESS)
1029 {
1030 Win32PeLdrDll *peldrDll;
1031
1032 //SvL: If executable -> load as data file (only resources)
1033 if(!(Characteristics & IMAGE_FILE_DLL))
1034 {
1035 dwFlags |= (LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES);
1036 }
1037
1038 peldrDll = new Win32PeLdrDll(szModname);
1039 if (peldrDll == NULL)
1040 {
1041 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Failed to created instance of Win32PeLdrDll. returns NULL.",
1042 lpszLibFile, hFile, dwFlags));
1043 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1044 return NULL;
1045 }
1046
1047 /** @sketch
1048 * Process dwFlags
1049 */
1050 if (dwFlags & LOAD_LIBRARY_AS_DATAFILE)
1051 {
1052 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): LOAD_LIBRARY_AS_DATAFILE",
1053 lpszLibFile, hFile, dwFlags));
1054 peldrDll->setLoadAsDataFile();
1055 peldrDll->disableLibraryCalls();
1056 }
1057 if (dwFlags & DONT_RESOLVE_DLL_REFERENCES)
1058 {
1059 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): DONT_RESOLVE_DLL_REFERENCES",
1060 lpszLibFile, hFile, dwFlags));
1061 peldrDll->disableLibraryCalls();
1062 peldrDll->disableImportHandling();
1063 }
1064 if (dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH)
1065 {
1066 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Warning dwFlags LOAD_WITH_ALTERED_SEARCH_PATH is not implemented.",
1067 lpszLibFile, hFile, dwFlags));
1068 //peldrDll->setLoadWithAlteredSearchPath();
1069 }
1070
1071 /** @sketch
1072 * Initiate the peldr DLL.
1073 * IF successful init THEN
1074 * Inc dynamic ref count.
1075 * Inc ref count.
1076 * Attach to process
1077 * IF successful THEN
1078 * hDLL <- instance handle.
1079 * ELSE
1080 * set last error
1081 * delete Win32PeLdrDll instance.
1082 * Endif
1083 * ELSE
1084 * set last error
1085 * delete Win32PeLdrDll instance.
1086 * Endif.
1087 */
1088 if (peldrDll->init(0))
1089 {
1090 peldrDll->AddRef();
1091 if (peldrDll->attachProcess())
1092 {
1093 hDll = peldrDll->getInstanceHandle();
1094 //Must be called *after* attachprocess, since attachprocess may also
1095 //trigger LoadLibrary calls
1096 //Those dlls must not be put in front of this dll in the dynamic
1097 //dll list; or else the unload order is wrong:
1098 //i.e. RPAP3260 loads PNRS3260 in DLL_PROCESS_ATTACH
1099 // this means that in ExitProcess, PNRS3260 needs to be removed
1100 // first since RPAP3260 depends on it
1101 peldrDll->incDynamicLib();
1102 }
1103 else
1104 {
1105 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): attachProcess call to Win32PeLdrDll instance failed. returns NULL.",
1106 lpszLibFile, hFile, dwFlags));
1107 SetLastError(ERROR_DLL_INIT_FAILED);
1108 delete peldrDll;
1109 return NULL;
1110 }
1111 }
1112 else
1113 {
1114 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Failed to init Win32PeLdrDll instance. error=%d returns NULL.",
1115 lpszLibFile, hFile, dwFlags, peldrDll->getError()));
1116 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
1117 delete peldrDll;
1118 return NULL;
1119 }
1120 }
1121 else
1122 {
1123 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x) library wasn't found (%s) or isn't loadable; err %x",
1124 lpszLibFile, hFile, dwFlags, szModname, fPE));
1125 SetLastError(fPE);
1126 return NULL;
1127 }
1128
1129 return hDll;
1130}
1131
1132
1133/**
1134 * LoadLibraryExW can be used to map a DLL module into the calling process's
1135 * addressspace. It returns a handle that can be used with GetProcAddress to
1136 * get addresses of exported entry points (functions and variables).
1137 *
1138 * LoadLibraryExW can also be used to map executable (.exe) modules into the
1139 * address to access resources in the module. However, LoadLibrary can't be
1140 * used to run an executable (.exe) module.
1141 *
1142 * @returns Handle to the library which was loaded.
1143 * @param lpszLibFile Pointer to Unicode string giving the name of
1144 * the executable image (either a Dll or an Exe) which is to
1145 * be loaded.
1146 *
1147 * If no extention is specified the default .DLL extention is
1148 * appended to the name. End the filename with an '.' if the
1149 * file does not have an extention (and don't want the .DLL
1150 * appended).
1151 *
1152 * If no path is specified, this API will use the Odin32
1153 * standard search strategy to find the file. This strategy
1154 * is described in the method Win32ImageBase::findDLL.
1155 * This may be alterned by the LOAD_WITH_ALTERED_SEARCH_PATH
1156 * flag, see below.
1157 *
1158 * This API likes to have backslashes (\), but will probably
1159 * accept forward slashes too. Win32 SDK docs says that it
1160 * should not contain forward slashes.
1161 *
1162 * Win32 SDK docs adds:
1163 * "The name specified is the file name of the module and
1164 * is not related to the name stored in the library module
1165 * itself, as specified by the LIBRARY keyword in the
1166 * module-definition (.def) file."
1167 *
1168 * @param hFile Reserved. Must be 0.
1169 *
1170 * @param dwFlags Flags which specifies the taken when loading the module.
1171 * The value 0 makes it identical to LoadLibraryA/W.
1172 *
1173 * Flags:
1174 *
1175 * DONT_RESOLVE_DLL_REFERENCES
1176 * (WinNT/2K feature): Don't load imported modules and
1177 * hence don't resolve imported symbols.
1178 * DllMain isn't called either. (Which is obvious since
1179 * it may use one of the importe symbols.)
1180 *
1181 * On the other hand, if this flag is NOT set, the system
1182 * load imported modules, resolves imported symbols, calls
1183 * DllMain for process and thread init and term (if wished
1184 * by the module).
1185 *
1186 * LOAD_LIBRARY_AS_DATAFILE
1187 * If this flag is set, the module is mapped into the
1188 * address space but is not prepared for execution. Though
1189 * it's preparted for resource API. Hence, you'll use this
1190 * flag when you want to load a DLL for extracting
1191 * messages or resources from it.
1192 *
1193 * The resulting handle can be used with any Odin32 API
1194 * which operates on resources.
1195 * (WinNt/2k supports all resource APIs while Win9x don't
1196 * support the specialized resource APIs: LoadBitmap,
1197 * LoadCursor, LoadIcon, LoadImage, LoadMenu.)
1198 *
1199 * LOAD_WITH_ALTERED_SEARCH_PATH
1200 * If this flag is set and lpszLibFile specifies a path
1201 * we'll use an alternative file search strategy to find
1202 * imported modules. This stratgy is simply to use the
1203 * path of the module being loaded instead of the path
1204 * of the executable module as the first location
1205 * to search for imported modules.
1206 *
1207 * If this flag is clear, the standard Odin32 standard
1208 * search strategy. See Win32ImageBase::findDll for
1209 * further information.
1210 *
1211 * @sketch Convert Unicode name to ascii.
1212 * Call LoadLibraryExA.
1213 * Free ascii string.
1214 * return handle from LoadLibraryExA.
1215 * @status Open32 Partially Implemented.
1216 * @author Sander van Leeuwen (sandervl@xs4all.nl)
1217 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
1218 * @remark Forwards to LoadLibraryExA.
1219 */
1220HINSTANCE WIN32API LoadLibraryExW(LPCWSTR lpszLibFile, HANDLE hFile, DWORD dwFlags)
1221{
1222 char * pszAsciiLibFile;
1223 HINSTANCE hDll;
1224
1225 pszAsciiLibFile = UnicodeToAsciiString(lpszLibFile);
1226 dprintf(("KERNEL32: LoadLibraryExW(%s, 0x%x, 0x%x) --> LoadLibraryExA",
1227 pszAsciiLibFile, hFile, dwFlags));
1228 hDll = LoadLibraryExA(pszAsciiLibFile, hFile, dwFlags);
1229 dprintf(("KERNEL32: LoadLibraryExW(%s, 0x%x, 0x%x) returns 0x%x",
1230 pszAsciiLibFile, hFile, dwFlags, hDll));
1231 FreeAsciiString(pszAsciiLibFile);
1232
1233 return hDll;
1234}
1235//******************************************************************************
1236//******************************************************************************
1237HINSTANCE16 WIN32API LoadLibrary16(LPCTSTR lpszLibFile)
1238{
1239 dprintf(("ERROR: LoadLibrary16 %s, not implemented", lpszLibFile));
1240 return 0;
1241}
1242//******************************************************************************
1243//******************************************************************************
1244VOID WIN32API FreeLibrary16(HINSTANCE16 hinstance)
1245{
1246 dprintf(("ERROR: FreeLibrary16 %x, not implemented", hinstance));
1247}
1248//******************************************************************************
1249//******************************************************************************
1250FARPROC WIN32API GetProcAddress16(HMODULE hModule, LPCSTR lpszProc)
1251{
1252 dprintf(("ERROR: GetProcAddress16 %x %x, not implemented", hModule, lpszProc));
1253 return 0;
1254}
1255
1256
1257/**
1258 * Internal function which gets the commandline (string) used to start the current process.
1259 * @returns OS/2 / Windows return code
1260 * On successful return (NO_ERROR) the global variables
1261 * pszCmdLineA and pszCmdLineW are set.
1262 *
1263 * @param pszPeExe Pass in the name of the PE exe of this process. We'll
1264 * us this as exename and skip the first argument (ie. argv[1]).
1265 * If NULL we'll use the commandline from OS/2 as it is.
1266 * @status Completely implemented and tested.
1267 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1268 */
1269ULONG InitCommandLine(const char *pszPeExe)
1270{
1271 PCHAR pib_pchcmd; /* PIB pointer to commandline. */
1272 CHAR szFilename[CCHMAXPATH]; /* Filename buffer used to get the exe filename in. */
1273 ULONG cch; /* Commandline string length. (including terminator) */
1274 PSZ psz; /* Temporary string pointer. */
1275 PSZ psz2; /* Temporary string pointer. */
1276 APIRET rc; /* OS/2 return code. */
1277 BOOL fQuotes; /* Flag used to remember if the exe filename should be in quotes. */
1278
1279 /** @sketch
1280 * Get commandline from the PIB.
1281 */
1282 pib_pchcmd = (PCHAR)OSLibGetPIB(PIB_PCHCMD);
1283
1284 /** @sketch
1285 * Two methods of making the commandline:
1286 * (1) The first argument is skipped and the second is used as exe filname.
1287 * This applies to PE.EXE launched processes only.
1288 * (2) No skipping. First argument is the exe filename.
1289 * This applies to all but PE.EXE launched processes.
1290 *
1291 * Note: We could do some code size optimization here. Much of the code for
1292 * the two methods are nearly identical.
1293 *
1294 */
1295 if(pszPeExe)
1296 {
1297 /** @sketch
1298 * Allocate memory for the commandline.
1299 * Build commandline:
1300 * Copy exe filename.
1301 * Add arguments.
1302 */
1303 cch = strlen(pszPeExe)+1;
1304
1305 // PH 2002-04-11
1306 // Note: intentional memory leak, pszCmdLineW will not be freed
1307 // or allocated after process startup
1308 pszCmdLineA = psz = (PSZ)malloc(cch);
1309 if (psz == NULL)
1310 {
1311 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed\n", pszPeExe, cch));
1312 return ERROR_NOT_ENOUGH_MEMORY;
1313 }
1314 strcpy((char *)pszCmdLineA, pszPeExe);
1315
1316 rc = NO_ERROR;
1317 }
1318 else
1319 {
1320 /** @sketch Method (2):
1321 * First we'll have to determin the size of the commandline.
1322 *
1323 * As we don't assume that OS/2 allways puts a fully qualified EXE name
1324 * as the first string, we'll check if it's empty - and get the modulename
1325 * in that case - and allways get the fully qualified filename.
1326 */
1327 if (pib_pchcmd == NULL || pib_pchcmd[0] == '\0')
1328 {
1329 rc = OSLibDosQueryModuleName(OSLibGetPIB(PIB_HMTE), sizeof(szFilename), szFilename);
1330 if (rc != NO_ERROR)
1331 {
1332 dprintf(("KERNEL32: InitCommandLine(%p): OSLibQueryModuleName(0x%x,...) failed with rc=%d\n",
1333 pszPeExe, OSLibGetPIB(PIB_HMTE), rc));
1334 return rc;
1335 }
1336 }
1337 else
1338 {
1339 rc = OSLibDosQueryPathInfo(pib_pchcmd, FIL_QUERYFULLNAME, szFilename, sizeof(szFilename));
1340 if (rc != NO_ERROR)
1341 {
1342 dprintf(("KERNEL32: InitCommandLine(%p): (info) OSLibDosQueryPathInfo failed with rc=%d\n", pszPeExe, rc));
1343 strcpy(szFilename, pib_pchcmd);
1344 rc = NO_ERROR;
1345 }
1346 }
1347
1348 /** @sketch
1349 * We're still measuring the size of the commandline:
1350 * Check if we have to quote the exe filename.
1351 * Determin the length of the executable name including quotes and '\0'-terminator.
1352 * Count the length of the arguments. (We here count's all argument strings.)
1353 */
1354 fQuotes = strchr(szFilename, ' ') != NULL;
1355 cch = strlen(szFilename) + fQuotes*2 + 1;
1356 if (pib_pchcmd != NULL)
1357 {
1358 psz2 = pib_pchcmd + strlen(pib_pchcmd) + 1;
1359 while (*psz2 != '\0')
1360 {
1361 register int cchTmp = strlen(psz2) + 1; /* + 1 is for terminator (psz2) and space (cch). */
1362 psz2 += cchTmp;
1363 cch += cchTmp;
1364 }
1365 }
1366
1367 /** @sketch
1368 * Allocate memory for the commandline.
1369 * Build commandline:
1370 * Copy exe filename.
1371 * Add arguments.
1372 */
1373 pszCmdLineA = psz = (PSZ)malloc(cch);
1374 if (psz == NULL)
1375 {
1376 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed\n", pszPeExe, cch));
1377 return ERROR_NOT_ENOUGH_MEMORY;
1378 }
1379
1380 if (fQuotes)
1381 *psz++ = '"';
1382 strcpy(psz, szFilename);
1383 psz += strlen(psz);
1384 if (fQuotes)
1385 {
1386 *psz++ = '"';
1387 *psz = '\0';
1388 }
1389
1390 if (pib_pchcmd != NULL)
1391 {
1392 psz2 = pib_pchcmd + strlen(pib_pchcmd) + 1;
1393 while (*psz2 != '\0')
1394 {
1395 register int cchTmp = strlen(psz2) + 1; /* + 1 is for terminator (psz). */
1396 *psz++ = ' '; /* add space */
1397 memcpy(psz, psz2, cchTmp);
1398 psz2 += cchTmp;
1399 psz += cchTmp - 1;
1400 }
1401 }
1402 }
1403
1404 /** @sketch
1405 * If successfully build ASCII commandline then convert it to UniCode.
1406 */
1407 if (rc == NO_ERROR)
1408 {
1409 // PH 2002-04-11
1410 // Note: intentional memory leak, pszCmdLineW will not be freed
1411 // or allocated after process startup
1412 cch = strlen(pszCmdLineA) + 1;
1413
1414 pszCmdLineW = (WCHAR*)malloc(cch * 2);
1415 if (pszCmdLineW != NULL) {
1416 //Translate from OS/2 to Windows codepage & ascii to unicode
1417 MultiByteToWideChar(CP_OEMCP, 0, pszCmdLineA, -1, (LPWSTR)pszCmdLineW, cch-1);
1418 ((LPWSTR)pszCmdLineW)[cch-1] = 0;
1419
1420 //ascii command line is still in OS/2 codepage, so convert it
1421 WideCharToMultiByte(CP_ACP, 0, pszCmdLineW, -1, (LPSTR)pszCmdLineA, cch-1, 0, NULL);
1422 ((LPSTR)pszCmdLineA)[cch-1] = 0;
1423 }
1424 else
1425 {
1426 DebugInt3();
1427 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed (2)\n", pszPeExe, cch));
1428 rc = ERROR_NOT_ENOUGH_MEMORY;
1429 }
1430 }
1431
1432 return rc;
1433}
1434
1435/**
1436 * Gets the command line of the current process.
1437 * @returns On success:
1438 * Command line of the current process. One single string.
1439 * The first part of the command line string is the executable filename
1440 * of the current process. It might be in quotes if it contains spaces.
1441 * The rest of the string is arguments.
1442 *
1443 * On error:
1444 * NULL. Last error set. (does Win32 set last error this?)
1445 * @sketch IF not inited THEN
1446 * Init commandline assuming !PE.EXE
1447 * IF init failes THEN set last error.
1448 * ENDIF
1449 * return ASCII/ANSI commandline.
1450 * @status Completely implemented and tested.
1451 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1452 * @remark The Ring-3 PeLdr is resposible for calling InitCommandLine before anyone
1453 * is able to call this function.
1454 */
1455LPCSTR WIN32API GetCommandLineA(VOID)
1456{
1457 /*
1458 * Check if the commandline is initiated.
1459 * If not we'll have to do it.
1460 * ASSUMES that if not inited this isn't a PE.EXE lauched process.
1461 */
1462 if (pszCmdLineA == NULL)
1463 {
1464 APIRET rc;
1465 rc = InitCommandLine(NULL);
1466 if (rc != NULL)
1467 SetLastError(rc);
1468 }
1469
1470 dprintf(("KERNEL32: GetCommandLineA: %s\n", pszCmdLineA));
1471 return pszCmdLineA;
1472}
1473
1474
1475/**
1476 * Gets the command line of the current process.
1477 * @returns On success:
1478 * Command line of the current process. One single string.
1479 * The first part of the command line string is the executable filename
1480 * of the current process. It might be in quotes if it contains spaces.
1481 * The rest of the string is arguments.
1482 *
1483 * On error:
1484 * NULL. Last error set. (does Win32 set last error this?)
1485 * @sketch IF not inited THEN
1486 * Init commandline assuming !PE.EXE
1487 * IF init failes THEN set last error.
1488 * ENDIF
1489 * return Unicode commandline.
1490 * @status Completely implemented and tested.
1491 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1492 * @remark The Ring-3 PeLdr is resposible for calling InitCommandLine before anyone
1493 * is able to call this function.
1494 */
1495LPCWSTR WIN32API GetCommandLineW(void)
1496{
1497 /*
1498 * Check if the commandline is initiated.
1499 * If not we'll have to do it.
1500 * ASSUMES that if not inited this isn't a PE.EXE lauched process.
1501 */
1502 if (pszCmdLineW == NULL)
1503 {
1504 APIRET rc;
1505 rc = InitCommandLine(NULL);
1506 if (rc != NULL)
1507 SetLastError(rc);
1508 }
1509
1510 dprintf(("KERNEL32: GetCommandLineW: %s\n", pszCmdLineA));
1511 return pszCmdLineW;
1512}
1513
1514
1515/**
1516 * GetModuleFileName gets the full path and file name for the specified module.
1517 * @returns Bytes written to the buffer (lpszPath). This count includes the
1518 * terminating '\0'.
1519 * On error 0 is returned. Last error is set.
1520 *
1521 * 2002-04-25 PH
1522 * Q - Do we set ERROR_BUFFER_OVERFLOW when cch > cchPath?
1523 * Q - Does NT really set the last error?
1524 * A > Win2k does not set LastError here, remains OK
1525 *
1526 * While GetModuleFileName does add a trailing termination zero
1527 * if there is enough room, the returned number of characters
1528 * *MUST NOT* include the zero character!
1529 * (Notes R6 Installer on Win2kSP6, verified Testcase)
1530 *
1531 * @param hModule Handle to the module you like to get the file name to.
1532 * @param lpszPath Output buffer for full path and file name.
1533 * @param cchPath Size of the lpszPath buffer.
1534 * @sketch Validate lpszPath.
1535 * Find the module object using handle.
1536 * If found Then
1537 * Get full path from module object.
1538 * If found path Then
1539 * Copy path to buffer and set the number of bytes written.
1540 * Else
1541 * IPE!
1542 * Else
1543 * Call Open32 GetModuleFileName. (kernel32 initterm needs/needed this)
1544 * Log result.
1545 * Return number of bytes written to the buffer.
1546 *
1547 * @status Completely implemented, Open32.
1548 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1549 * Sander van Leeuwen (sandervl@xs4all.nl)
1550 * Patrick Haller (patrick.haller@innotek.de)
1551 * @remark - Do we still have to call Open32?
1552 */
1553DWORD WIN32API GetModuleFileNameA(HMODULE hModule, LPTSTR lpszPath, DWORD cchPath)
1554{
1555 Win32ImageBase * pMod; /* Pointer to the module object. */
1556 DWORD cch = 0; /* Length of the */
1557
1558 // PH 2002-04-24 Note:
1559 // WIN2k just crashes in NTDLL if lpszPath is invalid!
1560 if (!VALID_PSZ(lpszPath))
1561 {
1562 dprintf(("KERNEL32: GetModuleFileNameA(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
1563 hModule, lpszPath, cchPath, lpszPath));
1564 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
1565 return 0;
1566 }
1567
1568 pMod = Win32ImageBase::findModule(hModule);
1569 if (pMod != NULL)
1570 {
1571 const char *pszFn = pMod->getFullPath();
1572 if (pszFn)
1573 {
1574 cch = strlen(pszFn);
1575 if (cch >= cchPath)
1576 cch = cchPath;
1577 else
1578 // if there is sufficient room for the zero termination,
1579 // write it additionally, uncounted
1580 lpszPath[cch] = '\0';
1581
1582 memcpy(lpszPath, pszFn, cch);
1583 }
1584 else
1585 {
1586 dprintf(("KERNEL32: GetModuleFileNameA(%x,...): IPE - getFullPath returned NULL or empty string\n"));
1587 DebugInt3();
1588 SetLastError(ERROR_INVALID_HANDLE);
1589 }
1590 }
1591 else
1592 {
1593 SetLastError(ERROR_INVALID_HANDLE);
1594 //only needed for call inside kernel32's initterm (profile init)
1595 //(console init only it seems...)
1596 cch = OSLibDosGetModuleFileName(hModule, lpszPath, cchPath);
1597 }
1598
1599 if (cch > 0)
1600 dprintf(("KERNEL32: GetModuleFileNameA(%x %x): %s %d\n", hModule, lpszPath, lpszPath, cch));
1601 else
1602 dprintf(("KERNEL32: WARNING: GetModuleFileNameA(%x,...) - not found!", hModule));
1603
1604 return cch;
1605}
1606
1607
1608/**
1609 * GetModuleFileName gets the full path and file name for the specified module.
1610 * @returns Bytes written to the buffer (lpszPath). This count includes the
1611 * terminating '\0'.
1612 * On error 0 is returned. Last error is set.
1613 * @param hModule Handle to the module you like to get the file name to.
1614 * @param lpszPath Output buffer for full path and file name.
1615 * @param cchPath Size of the lpszPath buffer.
1616 * @sketch Find the module object using handle.
1617 * If found Then
1618 * get full path from module object.
1619 * If found path Then
1620 * Determin path length.
1621 * Translate the path to into the buffer.
1622 * Else
1623 * IPE.
1624 * else
1625 * SetLastError to invalid handle.
1626 * Log result.
1627 * return number of bytes written to the buffer.
1628 *
1629 * @status Completely implemented.
1630 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1631 * @remark - We do _NOT_ call Open32.
1632 * - Do we set ERROR_BUFFER_OVERFLOW when cch > cchPath?
1633 * - Does NT really set the last error?
1634 */
1635DWORD WIN32API GetModuleFileNameW(HMODULE hModule, LPWSTR lpszPath, DWORD cchPath)
1636{
1637 Win32ImageBase * pMod;
1638 DWORD cch = 0;
1639
1640 if (!VALID_PSZ(lpszPath))
1641 {
1642 dprintf(("KERNEL32: GetModuleFileNameW(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
1643 hModule, lpszPath, cchPath, lpszPath));
1644 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
1645 return 0;
1646 }
1647
1648 pMod = Win32ImageBase::findModule(hModule);
1649 if (pMod != NULL)
1650 {
1651 const char *pszFn = pMod->getFullPath();
1652 if (pszFn || *pszFn != '\0')
1653 {
1654 cch = strlen(pszFn) + 1;
1655 if (cch > cchPath)
1656 cch = cchPath;
1657 AsciiToUnicodeN(pszFn, lpszPath, cch);
1658 }
1659 else
1660 {
1661 dprintf(("KERNEL32: GetModuleFileNameW(%x,...): IPE - getFullPath returned NULL or empty string\n"));
1662 DebugInt3();
1663 SetLastError(ERROR_INVALID_HANDLE);
1664 }
1665 }
1666 else
1667 SetLastError(ERROR_INVALID_HANDLE);
1668
1669 if (cch > 0)
1670 dprintf(("KERNEL32: GetModuleFileNameW(%x,...): %s %d\n", hModule, lpszPath, cch));
1671 else
1672 dprintf(("KERNEL32: WARNING: GetModuleFileNameW(%x,...) - not found!", hModule));
1673
1674 return cch;
1675}
1676
1677
1678//******************************************************************************
1679//NOTE: GetModuleHandleA does NOT support files with multiple dots (i.e.
1680// very.weird.exe)
1681//
1682// hinst = LoadLibrary("WINSPOOL.DRV"); -> succeeds
1683// hinst2 = GetModuleHandle("WINSPOOL.DRV"); -> succeeds
1684// hinst3 = GetModuleHandle("WINSPOOL."); -> fails
1685// hinst4 = GetModuleHandle("WINSPOOL"); -> fails
1686// hinst = LoadLibrary("KERNEL32.DLL"); -> succeeds
1687// hinst2 = GetModuleHandle("KERNEL32.DLL"); -> succeeds
1688// hinst3 = GetModuleHandle("KERNEL32."); -> fails
1689// hinst4 = GetModuleHandle("KERNEL32"); -> succeeds
1690// Same behaviour as observed in NT4, SP6
1691//******************************************************************************
1692HANDLE WIN32API GetModuleHandleA(LPCTSTR lpszModule)
1693{
1694 HANDLE hMod = 0;
1695 Win32DllBase *windll;
1696 char szModule[CCHMAXPATH];
1697 char *dot;
1698
1699 if(lpszModule == NULL)
1700 {
1701 if(WinExe)
1702 hMod = WinExe->getInstanceHandle();
1703 else
1704 {
1705 // // Just fail this API
1706 // hMod = 0;
1707 // SetLastError(ERROR_INVALID_HANDLE);
1708 // Wrong: in an ODIN32-LX environment, just
1709 // assume a fake handle
1710 hMod = -1;
1711 }
1712 }
1713 else
1714 {
1715 strcpy(szModule, OSLibStripPath((char *)lpszModule));
1716 strupr(szModule);
1717 dot = strchr(szModule, '.');
1718 if(dot == NULL) {
1719 //if no extension -> add .DLL (see SDK docs)
1720 strcat(szModule, DLL_EXTENSION);
1721 }
1722 else {
1723 if(dot[1] == 0) {
1724 //a trailing dot means the module has no extension (SDK docs)
1725 *dot = 0;
1726 }
1727 }
1728 if(WinExe && WinExe->matchModName(szModule)) {
1729 hMod = WinExe->getInstanceHandle();
1730 }
1731 else {
1732 windll = Win32DllBase::findModule(szModule);
1733 if(windll) {
1734 hMod = windll->getInstanceHandle();
1735 }
1736 }
1737 }
1738 dprintf(("KERNEL32: GetModuleHandle %s returned %X\n", lpszModule, hMod));
1739 return(hMod);
1740}
1741//******************************************************************************
1742//******************************************************************************
1743HMODULE WIN32API GetModuleHandleW(LPCWSTR lpwszModuleName)
1744{
1745 HMODULE rc;
1746 char *astring = NULL;
1747
1748 if (NULL != lpwszModuleName)
1749 astring = UnicodeToAsciiString((LPWSTR)lpwszModuleName);
1750
1751 rc = GetModuleHandleA(astring);
1752 dprintf(("KERNEL32: OS2GetModuleHandleW %s returned %X\n", astring, rc));
1753
1754 if (NULL != astring)
1755 FreeAsciiString(astring);
1756
1757 return(rc);
1758}
1759//******************************************************************************
1760//******************************************************************************
1761static char szPECmdLoader[260] = "";
1762static char szPEGUILoader[260] = "";
1763static char szNELoader[260] = "";
1764//******************************************************************************
1765//Set default paths for PE & NE loaders
1766//******************************************************************************
1767BOOL InitLoaders()
1768{
1769 sprintf(szPECmdLoader, "%s\\PEC.EXE", InternalGetSystemDirectoryA());
1770 sprintf(szPEGUILoader, "%s\\PE.EXE", InternalGetSystemDirectoryA());
1771 sprintf(szNELoader, "%s\\W16ODIN.EXE", InternalGetSystemDirectoryA());
1772
1773 return TRUE;
1774}
1775//******************************************************************************
1776//Override loader names (PEC, PE, W16ODIN)
1777//******************************************************************************
1778BOOL WIN32API ODIN_SetLoaders(LPCSTR pszPECmdLoader, LPCSTR pszPEGUILoader,
1779 LPCSTR pszNELoader)
1780{
1781 if(pszPECmdLoader) strcpy(szPECmdLoader, pszPECmdLoader);
1782 if(pszPEGUILoader) strcpy(szPEGUILoader, pszPEGUILoader);
1783 if(pszNELoader) strcpy(szNELoader, pszNELoader);
1784
1785 return TRUE;
1786}
1787//******************************************************************************
1788//******************************************************************************
1789BOOL WIN32API ODIN_QueryLoaders(LPSTR pszPECmdLoader, INT cchPECmdLoader,
1790 LPSTR pszPEGUILoader, INT cchPEGUILoader,
1791 LPSTR pszNELoader, INT cchNELoader)
1792{
1793 if(pszPECmdLoader) strncpy(pszPECmdLoader, szPECmdLoader, cchPECmdLoader);
1794 if(pszPEGUILoader) strncpy(pszPEGUILoader, szPEGUILoader, cchPEGUILoader);
1795 if(pszNELoader) strncpy(pszNELoader, szNELoader, cchNELoader);
1796
1797 return TRUE;
1798}
1799//******************************************************************************
1800//******************************************************************************
1801BOOL WINAPI CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine,
1802 LPSECURITY_ATTRIBUTES lpProcessAttributes,
1803 LPSECURITY_ATTRIBUTES lpThreadAttributes,
1804 BOOL bInheritHandles, DWORD dwCreationFlags,
1805 LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
1806 LPSTARTUPINFOA lpStartupInfo,
1807 LPPROCESS_INFORMATION lpProcessInfo )
1808{
1809 TEB *pThreadDB = (TEB*)GetThreadTEB();
1810 char *cmdline = NULL;
1811 BOOL rc;
1812
1813 dprintf(("KERNEL32: CreateProcessA %s cline:%s inherit:%d cFlags:%x Env:%x CurDir:%s StartupFlags:%x\n",
1814 lpApplicationName, lpCommandLine, bInheritHandles, dwCreationFlags,
1815 lpEnvironment, lpCurrentDirectory, lpStartupInfo));
1816
1817#ifdef DEBUG
1818 if(lpStartupInfo) {
1819 dprintf(("lpStartupInfo->lpReserved %x", lpStartupInfo->lpReserved));
1820 dprintf(("lpStartupInfo->lpDesktop %x", lpStartupInfo->lpDesktop));
1821 dprintf(("lpStartupInfo->lpTitle %s", lpStartupInfo->lpTitle));
1822 dprintf(("lpStartupInfo->dwX %x", lpStartupInfo->dwX));
1823 dprintf(("lpStartupInfo->dwY %x", lpStartupInfo->dwY));
1824 dprintf(("lpStartupInfo->dwXSize %x", lpStartupInfo->dwXSize));
1825 dprintf(("lpStartupInfo->dwYSize %x", lpStartupInfo->dwYSize));
1826 dprintf(("lpStartupInfo->dwXCountChars %x", lpStartupInfo->dwXCountChars));
1827 dprintf(("lpStartupInfo->dwYCountChars %x", lpStartupInfo->dwYCountChars));
1828 dprintf(("lpStartupInfo->dwFillAttribute %x", lpStartupInfo->dwFillAttribute));
1829 dprintf(("lpStartupInfo->dwFlags %x", lpStartupInfo->dwFlags));
1830 dprintf(("lpStartupInfo->wShowWindow %x", lpStartupInfo->wShowWindow));
1831 dprintf(("lpStartupInfo->hStdInput %x", lpStartupInfo->hStdInput));
1832 dprintf(("lpStartupInfo->hStdOutput %x", lpStartupInfo->hStdOutput));
1833 dprintf(("lpStartupInfo->hStdError %x", lpStartupInfo->hStdError));
1834 }
1835#endif
1836
1837 // open32 does not support DEBUG_ONLY_THIS_PROCESS
1838 if(dwCreationFlags & DEBUG_ONLY_THIS_PROCESS)
1839 dwCreationFlags |= DEBUG_PROCESS;
1840
1841 if(O32_CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes,
1842 lpThreadAttributes, bInheritHandles, dwCreationFlags,
1843 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
1844 lpProcessInfo) == TRUE)
1845 {
1846 if (dwCreationFlags & DEBUG_PROCESS && pThreadDB != NULL)
1847 {
1848 if(pThreadDB->o.odin.pidDebuggee != 0)
1849 {
1850 // TODO: handle this
1851 dprintf(("KERNEL32: CreateProcess ERROR: This thread is already a debugger\n"));
1852 }
1853 else
1854 {
1855 pThreadDB->o.odin.pidDebuggee = lpProcessInfo->dwProcessId;
1856 OSLibStartDebugger((ULONG*)&pThreadDB->o.odin.pidDebuggee);
1857 }
1858 }
1859 else pThreadDB->o.odin.pidDebuggee = 0;
1860
1861 return(TRUE);
1862 }
1863
1864 // PH 2001-05-07
1865 // verify why O32_CreateProcess actually failed.
1866 // If GetLastError() == 191 (ERROR_INVALID_EXE_SIGNATURE)
1867 // we can continue to call "PE.EXE".
1868 // Note: Open32 does not translate ERROR_INVALID_EXE_SIGNATURE,
1869 // it is also valid in Win32.
1870 DWORD dwError = GetLastError();
1871 if (ERROR_INVALID_EXE_SIGNATURE != dwError && ERROR_FILE_NOT_FOUND != dwError && ERROR_ACCESS_DENIED != dwError)
1872 {
1873 dprintf(("CreateProcess: O32_CreateProcess failed with rc=%d, not PE-executable !",
1874 dwError));
1875
1876 // the current value of GetLastError() is still valid.
1877
1878 return FALSE;
1879 }
1880
1881 // else ...
1882
1883 //probably a win32 exe, so run it in the pe loader
1884 if(lpApplicationName) {
1885 if(lpCommandLine) {
1886 //skip exe name in lpCommandLine
1887 //TODO: doesn't work for directories with spaces!
1888 while(*lpCommandLine != 0 && *lpCommandLine != ' ')
1889 lpCommandLine++;
1890
1891 if(*lpCommandLine != 0) {
1892 lpCommandLine++;
1893 }
1894 cmdline = (char *)malloc(strlen(lpApplicationName)+strlen(lpCommandLine) + 16);
1895 sprintf(cmdline, "%s %s", lpApplicationName, lpCommandLine);
1896 }
1897 else {
1898 cmdline = (char *)malloc(strlen(lpApplicationName) + 16);
1899 sprintf(cmdline, "%s", lpApplicationName);
1900 }
1901 }
1902 else {
1903 cmdline = (char *)malloc(strlen(lpCommandLine) + 16);
1904 sprintf(cmdline, "%s", lpCommandLine);
1905 }
1906
1907 char szAppName[MAX_PATH];
1908 char buffer[MAX_PATH];
1909 DWORD fileAttr;
1910 char *exename = buffer;
1911 strncpy(buffer, cmdline, sizeof(szAppName));
1912 buffer[MAX_PATH-1] = 0;
1913 if(*exename == '"') {
1914 exename++;
1915 while(*exename != 0 && *exename != '"')
1916 exename++;
1917
1918 if(*exename != 0) {
1919 *exename = 0;
1920 }
1921 exename++;
1922 if (SearchPathA( NULL, &buffer[1], ".exe", sizeof(szAppName), szAppName, NULL ) ||
1923 SearchPathA( NULL, &buffer[1], NULL, sizeof(szAppName), szAppName, NULL ))
1924 {
1925 //
1926 }
1927 }
1928 else {
1929 BOOL fTerminate = FALSE;
1930 DWORD fileAttr;
1931
1932 while(*exename != 0) {
1933 while(*exename != 0 && *exename != ' ')
1934 exename++;
1935
1936 if(*exename != 0) {
1937 *exename = 0;
1938 fTerminate = TRUE;
1939 }
1940 dprintf(("Trying '%s'", buffer ));
1941 if (SearchPathA( NULL, buffer, ".exe", sizeof(szAppName), szAppName, NULL ) ||
1942 SearchPathA( NULL, buffer, NULL, sizeof(szAppName), szAppName, NULL ))
1943 {
1944 if(fTerminate) exename++;
1945 break;
1946 }
1947
1948 if(fTerminate) {
1949 *exename = ' ';
1950 exename++;
1951 fTerminate = FALSE;
1952 }
1953 }
1954 }
1955 lpCommandLine = exename; //start of command line parameters
1956
1957 fileAttr = GetFileAttributesA(szAppName);
1958 if(fileAttr == -1 || (fileAttr & FILE_ATTRIBUTE_DIRECTORY)) {
1959 dprintf(("CreateProcess: can't find executable!"));
1960 SetLastError(ERROR_FILE_NOT_FOUND);
1961 return FALSE;
1962 }
1963
1964 dprintf(("KERNEL32: CreateProcess %s %s", szAppName, lpCommandLine));
1965
1966 DWORD Characteristics, SubSystem, fNEExe;
1967 if(Win32ImageBase::isPEImage(szAppName, &Characteristics, &SubSystem, &fNEExe) == 0)
1968 {
1969 char *lpszPE;
1970 char *lpszExecutable;
1971 int iNewCommandLineLength;
1972
1973 // calculate base length for the new command line
1974 iNewCommandLineLength = strlen(szAppName) + strlen(lpCommandLine);
1975
1976 if(SubSystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
1977 lpszExecutable = (LPSTR)szPECmdLoader;
1978 else
1979 lpszExecutable = (LPSTR)szPEGUILoader;
1980
1981 lpszPE = lpszExecutable;
1982
1983 // 2002-04-24 PH
1984 // set the ODIN32.DEBUG_CHILD environment variable to start new PE processes
1985 // under a new instance of the (IPMD) debugger.
1986#ifdef DEBUG
1987 CHAR debug_szPE[ 512 ];
1988 PSZ debug_pszOS2Debugger = getenv("ODIN32.DEBUG_CHILD");
1989 if (NULL != debug_pszOS2Debugger)
1990 {
1991 // build new start command
1992 strcpy(debug_szPE, debug_pszOS2Debugger);
1993 strcat(debug_szPE, " ");
1994 strcat(debug_szPE, lpszExecutable);
1995
1996 // we require more space in the new command line
1997 iNewCommandLineLength += strlen( debug_szPE );
1998
1999 // only launch the specified executable (ICSDEBUG.EXE)
2000 lpszPE = debug_szPE;
2001 lpszExecutable = debug_pszOS2Debugger;
2002 }
2003#endif
2004
2005 //SvL: Allright. Before we call O32_CreateProcess, we must take care of
2006 // lpCurrentDirectory ourselves. (Open32 ignores it!)
2007 if(lpCurrentDirectory) {
2008 char *newcmdline;
2009
2010 newcmdline = (char *)malloc(strlen(lpCurrentDirectory) + iNewCommandLineLength + 32);
2011 sprintf(newcmdline, "%s /OPT:[CURDIR=%s] %s %s", lpszPE, lpCurrentDirectory, szAppName, lpCommandLine);
2012 free(cmdline);
2013 cmdline = newcmdline;
2014 }
2015 else {
2016 char *newcmdline;
2017
2018 newcmdline = (char *)malloc(iNewCommandLineLength + 16);
2019 sprintf(newcmdline, "%s %s %s", lpszPE, szAppName, lpCommandLine);
2020 free(cmdline);
2021 cmdline = newcmdline;
2022 }
2023
2024 dprintf(("KERNEL32: CreateProcess starting [%s],[%s]",
2025 lpszExecutable,
2026 cmdline));
2027
2028 rc = O32_CreateProcess(lpszExecutable, (LPCSTR)cmdline,lpProcessAttributes,
2029 lpThreadAttributes, bInheritHandles, dwCreationFlags,
2030 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
2031 lpProcessInfo);
2032 }
2033 else
2034 if(fNEExe) {//16 bits windows app
2035 char *newcmdline;
2036
2037 newcmdline = (char *)malloc(strlen(szAppName) + strlen(cmdline) + 512);
2038
2039 sprintf(newcmdline, "%s /PELDR=[%s] %s", szNELoader, szPEGUILoader, szAppName, lpCommandLine);
2040 free(cmdline);
2041 cmdline = newcmdline;
2042 //Force Open32 to use DosStartSession (DosExecPgm won't do)
2043 dwCreationFlags |= CREATE_NEW_PROCESS_GROUP;
2044
2045 dprintf(("KERNEL32: CreateProcess starting [%s],[%s]",
2046 szNELoader,
2047 cmdline));
2048 rc = O32_CreateProcess(szNELoader, (LPCSTR)cmdline, lpProcessAttributes,
2049 lpThreadAttributes, bInheritHandles, dwCreationFlags,
2050 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
2051 lpProcessInfo);
2052 }
2053 else {//os/2 app??
2054 rc = O32_CreateProcess(szAppName, (LPCSTR)lpCommandLine, lpProcessAttributes,
2055 lpThreadAttributes, bInheritHandles, dwCreationFlags,
2056 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
2057 lpProcessInfo);
2058 }
2059 if(rc == TRUE)
2060 {
2061 if (dwCreationFlags & DEBUG_PROCESS && pThreadDB != NULL)
2062 {
2063 if(pThreadDB->o.odin.pidDebuggee != 0)
2064 {
2065 // TODO: handle this
2066 dprintf(("KERNEL32: CreateProcess ERROR: This thread is already a debugger\n"));
2067 }
2068 else
2069 {
2070 pThreadDB->o.odin.pidDebuggee = lpProcessInfo->dwProcessId;
2071 OSLibStartDebugger((ULONG*)&pThreadDB->o.odin.pidDebuggee);
2072 }
2073 }
2074 else
2075 pThreadDB->o.odin.pidDebuggee = 0;
2076 }
2077 if(cmdline)
2078 free(cmdline);
2079
2080 if(lpProcessInfo)
2081 {
2082 lpProcessInfo->dwThreadId = MAKE_THREADID(lpProcessInfo->dwProcessId, lpProcessInfo->dwThreadId);
2083 dprintf(("KERNEL32: CreateProcess returned %d hPro:%x hThr:%x pid:%x tid:%x\n",
2084 rc, lpProcessInfo->hProcess, lpProcessInfo->hThread,
2085 lpProcessInfo->dwProcessId,lpProcessInfo->dwThreadId));
2086 }
2087 else
2088 dprintf(("KERNEL32: CreateProcess returned %d\n", rc));
2089 return(rc);
2090}
2091//******************************************************************************
2092//******************************************************************************
2093BOOL WIN32API CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
2094 PSECURITY_ATTRIBUTES lpProcessAttributes,
2095 PSECURITY_ATTRIBUTES lpThreadAttributes,
2096 BOOL bInheritHandles, DWORD dwCreationFlags,
2097 LPVOID lpEnvironment,
2098 LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
2099 LPPROCESS_INFORMATION lpProcessInfo)
2100{
2101 BOOL rc;
2102 char *astring1 = 0, *astring2 = 0, *astring3 = 0;
2103
2104 dprintf(("KERNEL32: CreateProcessW"));
2105 if(lpApplicationName)
2106 astring1 = UnicodeToAsciiString((LPWSTR)lpApplicationName);
2107 if(lpCommandLine)
2108 astring2 = UnicodeToAsciiString(lpCommandLine);
2109 if(lpCurrentDirectory)
2110 astring3 = UnicodeToAsciiString((LPWSTR)lpCurrentDirectory);
2111 rc = CreateProcessA(astring1, astring2, lpProcessAttributes, lpThreadAttributes,
2112 bInheritHandles, dwCreationFlags, lpEnvironment,
2113 astring3, (LPSTARTUPINFOA)lpStartupInfo,
2114 lpProcessInfo);
2115 if(astring3) FreeAsciiString(astring3);
2116 if(astring2) FreeAsciiString(astring2);
2117 if(astring1) FreeAsciiString(astring1);
2118 return(rc);
2119}
2120//******************************************************************************
2121//******************************************************************************
2122HINSTANCE WIN32API WinExec(LPCSTR lpCmdLine, UINT nCmdShow)
2123{
2124 STARTUPINFOA startinfo = {0};
2125 PROCESS_INFORMATION procinfo;
2126 DWORD rc;
2127 HINSTANCE hInstance;
2128
2129 dprintf(("KERNEL32: WinExec %s\n", lpCmdLine));
2130 startinfo.dwFlags = nCmdShow;
2131 if(CreateProcessA(NULL, (LPSTR)lpCmdLine, NULL, NULL, FALSE, 0, NULL, NULL,
2132 &startinfo, &procinfo) == FALSE)
2133 {
2134 hInstance = (HINSTANCE)GetLastError();
2135 if(hInstance >= 32) {
2136 hInstance = 11;
2137 }
2138 dprintf(("KERNEL32: WinExec failed with rc %d", hInstance));
2139 return hInstance;
2140 }
2141 //block until the launched app waits for input (or a timeout of 15 seconds)
2142 //TODO: Shouldn't call Open32, but the api in user32..
2143 if(fVersionWarp3) {
2144 Sleep(1000); //WaitForInputIdle not available in Warp 3
2145 }
2146 else {
2147 dprintf(("Calling WaitForInputIdle %x %d", procinfo.hProcess, 15000));
2148 rc = WaitForInputIdle(procinfo.hProcess, 15000);
2149#ifdef DEBUG
2150 if(rc != 0) {
2151 dprintf(("WinExec: WaitForInputIdle %x returned %x", procinfo.hProcess, rc));
2152 }
2153 else dprintf(("WinExec: WaitForInputIdle successfull"));
2154#endif
2155 }
2156 CloseHandle(procinfo.hThread);
2157 CloseHandle(procinfo.hProcess);
2158 return 33;
2159}
2160//******************************************************************************
2161//DWORD idAttach; /* thread to attach */
2162//DWORD idAttachTo; /* thread to attach to */
2163//BOOL fAttach; /* attach or detach */
2164//******************************************************************************
2165BOOL WIN32API AttachThreadInput(DWORD idAttach, DWORD idAttachTo, BOOL fAttach)
2166{
2167 dprintf(("USER32: AttachThreadInput, not implemented\n"));
2168 return(TRUE);
2169}
2170//******************************************************************************
2171//******************************************************************************
2172DWORD WIN32API WaitForInputIdle(HANDLE hProcess, DWORD dwTimeOut)
2173{
2174 dprintf(("USER32: WaitForInputIdle %x %d\n", hProcess, dwTimeOut));
2175
2176 if(fVersionWarp3) {
2177 Sleep(1000);
2178 return 0;
2179 }
2180 else return O32_WaitForInputIdle(hProcess, dwTimeOut);
2181}
2182/**********************************************************************
2183 * LoadModule (KERNEL32.499)
2184 *
2185 * Wine: 20000909
2186 *
2187 * Copyright 1995 Alexandre Julliard
2188 */
2189HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock )
2190{
2191 LOADPARAMS *params = (LOADPARAMS *)paramBlock;
2192 PROCESS_INFORMATION info;
2193 STARTUPINFOA startup;
2194 HINSTANCE hInstance;
2195 LPSTR cmdline, p;
2196 char filename[MAX_PATH];
2197 BYTE len;
2198
2199 dprintf(("LoadModule %s %x", name, paramBlock));
2200
2201 if (!name) return ERROR_FILE_NOT_FOUND;
2202
2203 if (!SearchPathA( NULL, name, ".exe", sizeof(filename), filename, NULL ) &&
2204 !SearchPathA( NULL, name, NULL, sizeof(filename), filename, NULL ))
2205 return GetLastError();
2206
2207 len = (BYTE)params->lpCmdLine[0];
2208 if (!(cmdline = (LPSTR)HeapAlloc( GetProcessHeap(), 0, strlen(filename) + len + 2 )))
2209 return ERROR_NOT_ENOUGH_MEMORY;
2210
2211 strcpy( cmdline, filename );
2212 p = cmdline + strlen(cmdline);
2213 *p++ = ' ';
2214 memcpy( p, params->lpCmdLine + 1, len );
2215 p[len] = 0;
2216
2217 memset( &startup, 0, sizeof(startup) );
2218 startup.cb = sizeof(startup);
2219 if (params->lpCmdShow)
2220 {
2221 startup.dwFlags = STARTF_USESHOWWINDOW;
2222 startup.wShowWindow = params->lpCmdShow[1];
2223 }
2224
2225 if (CreateProcessA( filename, cmdline, NULL, NULL, FALSE, 0,
2226 params->lpEnvAddress, NULL, &startup, &info ))
2227 {
2228 /* Give 15 seconds to the app to come up */
2229 if ( WaitForInputIdle ( info.hProcess, 15000 ) == 0xFFFFFFFF )
2230 dprintf(("ERROR: WaitForInputIdle failed: Error %ld\n", GetLastError() ));
2231 hInstance = 33;
2232 /* Close off the handles */
2233 CloseHandle( info.hThread );
2234 CloseHandle( info.hProcess );
2235 }
2236 else if ((hInstance = GetLastError()) >= 32)
2237 {
2238 dprintf(("ERROR: Strange error set by CreateProcess: %d\n", hInstance ));
2239 hInstance = 11;
2240 }
2241
2242 HeapFree( GetProcessHeap(), 0, cmdline );
2243 return hInstance;
2244}
2245//******************************************************************************
2246//******************************************************************************
2247FARPROC WIN32API GetProcAddress(HMODULE hModule, LPCSTR lpszProc)
2248{
2249 Win32ImageBase *winmod;
2250 FARPROC proc;
2251 ULONG ulAPIOrdinal;
2252
2253 if(hModule == 0 || hModule == -1 || (WinExe && hModule == WinExe->getInstanceHandle())) {
2254 winmod = WinExe;
2255 }
2256 else winmod = (Win32ImageBase *)Win32DllBase::findModule((HINSTANCE)hModule);
2257
2258 if(winmod) {
2259 ulAPIOrdinal = (ULONG)lpszProc;
2260 if (ulAPIOrdinal <= 0x0000FFFF) {
2261 proc = (FARPROC)winmod->getApi((int)ulAPIOrdinal);
2262 }
2263 else proc = (FARPROC)winmod->getApi((char *)lpszProc);
2264 if(proc == 0) {
2265#ifdef DEBUG
2266 if(ulAPIOrdinal <= 0x0000FFFF) {
2267 dprintf(("GetProcAddress %x %x not found!", hModule, ulAPIOrdinal));
2268 }
2269 else dprintf(("GetProcAddress %x %s not found!", hModule, lpszProc));
2270#endif
2271 SetLastError(ERROR_PROC_NOT_FOUND);
2272 }
2273 if(HIWORD(lpszProc))
2274 dprintf(("KERNEL32: GetProcAddress %s from %X returned %X\n", lpszProc, hModule, proc));
2275 else dprintf(("KERNEL32: GetProcAddress %x from %X returned %X\n", lpszProc, hModule, proc));
2276
2277 SetLastError(ERROR_SUCCESS);
2278 return proc;
2279 }
2280 proc = (FARPROC)OSLibDosGetProcAddress(hModule, lpszProc);
2281 if(HIWORD(lpszProc))
2282 dprintf(("KERNEL32: GetProcAddress %s from %X returned %X\n", lpszProc, hModule, proc));
2283 else dprintf(("KERNEL32: GetProcAddress %x from %X returned %X\n", lpszProc, hModule, proc));
2284 SetLastError(ERROR_SUCCESS);
2285 return(proc);
2286}
2287//******************************************************************************
2288//Retrieve the version
2289//******************************************************************************
2290BOOL SYSTEM GetVersionStruct(char *lpszModName, char *verstruct, ULONG bufLength)
2291{
2292 Win32ImageBase *winimage;
2293 HINSTANCE hDll;
2294 BOOL rc = FALSE;
2295
2296 dprintf(("GetVersionStruct of module %s %x %d", lpszModName, verstruct, bufLength));
2297 if(verstruct == NULL) {
2298 SetLastError(ERROR_INVALID_PARAMETER);
2299 return FALSE;
2300 }
2301 if (WinExe != NULL && WinExe->matchModName(lpszModName)) {
2302 return WinExe->getVersionStruct(verstruct, bufLength);
2303 }
2304 hDll = LoadLibraryExA(lpszModName, 0, LOAD_LIBRARY_AS_DATAFILE);
2305 if(hDll == 0) {
2306 dprintf(("ERROR: GetVersionStruct: Unable to load module!!"));
2307 return 0;
2308 }
2309 winimage = (Win32ImageBase *)Win32DllBase::findModule(hDll);
2310 if(winimage != NULL) {
2311 rc = winimage->getVersionStruct(verstruct, bufLength);
2312 }
2313 else {
2314 dprintf(("GetVersionStruct; just loaded dll %s, but can't find it now!", lpszModName));
2315//// DebugInt3();
2316 }
2317 FreeLibrary(hDll);
2318 return rc;
2319}
2320//******************************************************************************
2321//******************************************************************************
2322ULONG SYSTEM GetVersionSize(char *lpszModName)
2323{
2324 Win32ImageBase *winimage;
2325 HINSTANCE hDll;
2326 ULONG size = 0;
2327
2328 dprintf(("GetVersionSize of %s", lpszModName));
2329 if (WinExe != NULL && WinExe->matchModName(lpszModName)) {
2330 return WinExe->getVersionSize();
2331 }
2332
2333 hDll = LoadLibraryExA(lpszModName, 0, LOAD_LIBRARY_AS_DATAFILE);
2334 if(hDll == 0) {
2335 dprintf(("ERROR: GetVersionStruct: Unable to load module!!"));
2336 return 0;
2337 }
2338 winimage = (Win32ImageBase *)Win32DllBase::findModule(hDll);
2339 if(winimage != NULL) {
2340 size = winimage->getVersionSize();
2341 }
2342 else {
2343 dprintf(("GetVersionSize; just loaded dll %s, but can't find it now!", lpszModName));
2344//// DebugInt3();
2345 }
2346 FreeLibrary(hDll);
2347 return size;
2348}
2349//******************************************************************************
2350//******************************************************************************
2351BOOL WIN32API DisableThreadLibraryCalls(HMODULE hModule)
2352{
2353 Win32DllBase *winmod;
2354 FARPROC proc;
2355 ULONG ulAPIOrdinal;
2356
2357 winmod = Win32DllBase::findModule((HINSTANCE)hModule);
2358 if(winmod)
2359 {
2360 // don't call ATTACH/DETACH thread functions in DLL
2361 winmod->disableThreadLibraryCalls();
2362 return TRUE;
2363 }
2364 else
2365 {
2366 // raise error condition
2367 SetLastError(ERROR_INVALID_HANDLE);
2368 return FALSE;
2369 }
2370}
2371//******************************************************************************
2372//******************************************************************************
Note: See TracBrowser for help on using the repository browser.