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

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

Removed obsolete code for Glide drivers and IOPL

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