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

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

log time it takes to complete ExitProcess

File size: 91.3 KB
Line 
1/* $Id: wprocess.cpp,v 1.170 2003-01-06 14:43:51 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#include <odinpe.h>
34
35#include "odin32validate.h"
36#include "exceptutil.h"
37#include "asmutil.h"
38#include "oslibdos.h"
39#include "oslibmisc.h"
40#include "oslibdebug.h"
41#include "hmcomm.h"
42
43#include "console.h"
44#include "wincon.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 (time %x)", exitcode, GetCurrentTime()));
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 dprintf(("KERNEL32: ExitProcess done (time %x)", GetCurrentTime()));
571 O32_ExitProcess(exitcode);
572}
573//******************************************************************************
574//******************************************************************************
575BOOL WIN32API FreeLibrary(HINSTANCE hinstance)
576{
577 Win32DllBase *winmod;
578 BOOL rc;
579
580 SetLastError(ERROR_SUCCESS);
581 //SvL: Ignore FreeLibary for executable
582 if(WinExe && hinstance == WinExe->getInstanceHandle()) {
583 return TRUE;
584 }
585
586 winmod = Win32DllBase::findModule(hinstance);
587 if(winmod) {
588 dprintf(("FreeLibrary %s", winmod->getName()));
589 //Only free it when the nrDynamicLibRef != 0
590 //This prevent problems after ExitProcess:
591 //i.e. dll A is referenced by our exe and loaded with LoadLibrary by dll B
592 // During ExitProcess it's unloaded once (before dll B), dll B calls
593 // FreeLibrary, but our exe also has a reference -> unloaded too many times
594 if(winmod->isDynamicLib()) {
595 winmod->decDynamicLib();
596 winmod->Release();
597 }
598 else {
599 dprintf(("Skipping dynamic unload as nrDynamicLibRef == 0"));
600 }
601 return(TRUE);
602 }
603 dprintf(("WARNING: KERNEL32: FreeLibrary %s %x NOT FOUND!", OSLibGetDllName(hinstance), hinstance));
604 return(TRUE);
605}
606/*****************************************************************************
607 * Name : VOID WIN32API FreeLibraryAndExitThread
608 * Purpose : The FreeLibraryAndExitThread function decrements the reference
609 * count of a loaded dynamic-link library (DLL) by one, and then
610 * calls ExitThread to terminate the calling thread.
611 * The function does not return.
612 *
613 * The FreeLibraryAndExitThread function gives threads that are
614 * created and executed within a dynamic-link library an opportunity
615 * to safely unload the DLL and terminate themselves.
616 * Parameters:
617 * Variables :
618 * Result :
619 * Remark :
620 *****************************************************************************/
621VOID WIN32API FreeLibraryAndExitThread( HMODULE hLibModule, DWORD dwExitCode)
622{
623
624 dprintf(("KERNEL32: FreeLibraryAndExitThread(%08x,%08x)", hLibModule, dwExitCode));
625 FreeLibrary(hLibModule);
626 ExitThread(dwExitCode);
627}
628/******************************************************************************/
629/******************************************************************************/
630/**
631 * LoadLibraryA can be used to map a DLL module into the calling process's
632 * addressspace. It returns a handle that can be used with GetProcAddress to
633 * get addresses of exported entry points (functions and variables).
634 *
635 * LoadLibraryA can also be used to map executable (.exe) modules into the
636 * address to access resources in the module. However, LoadLibrary can't be
637 * used to run an executable (.exe) module.
638 *
639 * @returns Handle to the library which was loaded.
640 * @param lpszLibFile Pointer to zero ASCII string giving the name of the
641 * executable image (either a Dll or an Exe) which is to be
642 * loaded.
643 *
644 * If no extention is specified the default .DLL extention is
645 * appended to the name. End the filename with an '.' if the
646 * file does not have an extention (and don't want the .DLL
647 * appended).
648 *
649 * If no path is specified, this API will use the Odin32
650 * standard search strategy to find the file. This strategy
651 * is described in the method Win32ImageBase::findDLL.
652 *
653 * This API likes to have backslashes (\), but will probably
654 * accept forward slashes too. Win32 SDK docs says that it
655 * should not contain forward slashes.
656 *
657 * Win32 SDK docs adds:
658 * "The name specified is the file name of the module and
659 * is not related to the name stored in the library module
660 * itself, as specified by the LIBRARY keyword in the
661 * module-definition (.def) file."
662 *
663 * @sketch Call LoadLibraryExA with flags set to 0.
664 * @status Odin32 Completely Implemented.
665 * @author Sander van Leeuwen (sandervl@xs4all.nl)
666 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
667 * @remark Forwards to LoadLibraryExA.
668 */
669HINSTANCE WIN32API LoadLibraryA(LPCTSTR lpszLibFile)
670{
671 HINSTANCE hDll;
672
673 dprintf(("KERNEL32: LoadLibraryA(%s) --> LoadLibraryExA(lpszLibFile, 0, 0)",
674 lpszLibFile));
675 hDll = LoadLibraryExA(lpszLibFile, 0, 0);
676 dprintf(("KERNEL32: LoadLibraryA(%s) returns 0x%x",
677 lpszLibFile, hDll));
678 return hDll;
679}
680
681
682/**
683 * LoadLibraryW can be used to map a DLL module into the calling process's
684 * addressspace. It returns a handle that can be used with GetProcAddress to
685 * get addresses of exported entry points (functions and variables).
686 *
687 * LoadLibraryW can also be used to map executable (.exe) modules into the
688 * address to access resources in the module. However, LoadLibrary can't be
689 * used to run an executable (.exe) module.
690 *
691 * @returns Handle to the library which was loaded.
692 * @param lpszLibFile Pointer to Unicode string giving the name of
693 * the executable image (either a Dll or an Exe) which is to
694 * be loaded.
695 *
696 * If no extention is specified the default .DLL extention is
697 * appended to the name. End the filename with an '.' if the
698 * file does not have an extention (and don't want the .DLL
699 * appended).
700 *
701 * If no path is specified, this API will use the Odin32
702 * standard search strategy to find the file. This strategy
703 * is described in the method Win32ImageBase::findDLL.
704 *
705 * This API likes to have backslashes (\), but will probably
706 * accept forward slashes too. Win32 SDK docs says that it
707 * should not contain forward slashes.
708 *
709 * Win32 SDK docs adds:
710 * "The name specified is the file name of the module and
711 * is not related to the name stored in the library module
712 * itself, as specified by the LIBRARY keyword in the
713 * module-definition (.def) file."
714 *
715 * @sketch Convert Unicode name to ascii.
716 * Call LoadLibraryExA with flags set to 0.
717 * free ascii string.
718 * @status Odin32 Completely Implemented.
719 * @author Sander van Leeuwen (sandervl@xs4all.nl)
720 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
721 * @remark Forwards to LoadLibraryExA.
722 */
723HINSTANCE WIN32API LoadLibraryW(LPCWSTR lpszLibFile)
724{
725 char * pszAsciiLibFile;
726 HINSTANCE hDll;
727
728 pszAsciiLibFile = UnicodeToAsciiString(lpszLibFile);
729 dprintf(("KERNEL32: LoadLibraryW(%s) --> LoadLibraryExA(lpszLibFile, 0, 0)",
730 pszAsciiLibFile));
731 hDll = LoadLibraryExA(pszAsciiLibFile, NULL, 0);
732 dprintf(("KERNEL32: LoadLibraryW(%s) returns 0x%x",
733 pszAsciiLibFile, hDll));
734 FreeAsciiString(pszAsciiLibFile);
735
736 return hDll;
737}
738
739//******************************************************************************
740//Custom build function to disable loading of LX dlls
741static BOOL fDisableLXDllLoading = FALSE;
742//******************************************************************************
743void WIN32API ODIN_DisableLXDllLoading()
744{
745 fDisableLXDllLoading = TRUE;
746}
747
748/**
749 * LoadLibraryExA can be used to map a DLL module into the calling process's
750 * addressspace. It returns a handle that can be used with GetProcAddress to
751 * get addresses of exported entry points (functions and variables).
752 *
753 * LoadLibraryExA can also be used to map executable (.exe) modules into the
754 * address to access resources in the module. However, LoadLibrary can't be
755 * used to run an executable (.exe) module.
756 *
757 * @returns Handle to the library which was loaded.
758 * @param lpszLibFile Pointer to Unicode string giving the name of
759 * the executable image (either a Dll or an Exe) which is to
760 * be loaded.
761 *
762 * If no extention is specified the default .DLL extention is
763 * appended to the name. End the filename with an '.' if the
764 * file does not have an extention (and don't want the .DLL
765 * appended).
766 *
767 * If no path is specified, this API will use the Odin32
768 * standard search strategy to find the file. This strategy
769 * is described in the method Win32ImageBase::findDLL.
770 * This may be alterned by the LOAD_WITH_ALTERED_SEARCH_PATH
771 * flag, see below.
772 *
773 * This API likes to have backslashes (\), but will probably
774 * accept forward slashes too. Win32 SDK docs says that it
775 * should not contain forward slashes.
776 *
777 * Win32 SDK docs adds:
778 * "The name specified is the file name of the module and
779 * is not related to the name stored in the library module
780 * itself, as specified by the LIBRARY keyword in the
781 * module-definition (.def) file."
782 *
783 * @param hFile Reserved. Must be 0.
784 *
785 * @param dwFlags Flags which specifies the taken when loading the module.
786 * The value 0 makes it identical to LoadLibraryA/W.
787 *
788 * Flags:
789 *
790 * DONT_RESOLVE_DLL_REFERENCES
791 * (WinNT/2K feature): Don't load imported modules and
792 * hence don't resolve imported symbols.
793 * DllMain isn't called either. (Which is obvious since
794 * it may use one of the importe symbols.)
795 *
796 * On the other hand, if this flag is NOT set, the system
797 * load imported modules, resolves imported symbols, calls
798 * DllMain for process and thread init and term (if wished
799 * by the module).
800 *
801 *
802 * LOAD_LIBRARY_AS_DATAFILE
803 * If this flag is set, the module is mapped into the
804 * address space but is not prepared for execution. Though
805 * it's preparted for resource API. Hence, you'll use this
806 * flag when you want to load a DLL for extracting
807 * messages or resources from it.
808 *
809 * The resulting handle can be used with any Odin32 API
810 * which operates on resources.
811 * (WinNt/2k supports all resource APIs while Win9x don't
812 * support the specialized resource APIs: LoadBitmap,
813 * LoadCursor, LoadIcon, LoadImage, LoadMenu.)
814 *
815 *
816 * LOAD_WITH_ALTERED_SEARCH_PATH
817 * If this flag is set and lpszLibFile specifies a path
818 * we'll use an alternative file search strategy to find
819 * imported modules. This stratgy is simply to use the
820 * path of the module being loaded instead of the path
821 * of the executable module as the first location
822 * to search for imported modules.
823 *
824 * If this flag is clear, the standard Odin32 standard
825 * search strategy. See Win32ImageBase::findDll for
826 * further information.
827 *
828 * not implemented yet.
829 *
830 * @status Open32 Partially Implemented.
831 * @author Sander van Leeuwen (sandervl@xs4all.nl)
832 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
833 * @remark Forwards to LoadLibraryExA.
834 */
835HINSTANCE WIN32API LoadLibraryExA(LPCTSTR lpszLibFile, HANDLE hFile, DWORD dwFlags)
836{
837 HINSTANCE hDll;
838 Win32DllBase * pModule;
839 char szModname[CCHMAXPATH];
840 BOOL fPath; /* Flags which is set if the */
841 /* lpszLibFile contains a path. */
842 ULONG fPE; /* isPEImage return value. */
843 DWORD Characteristics; //file header's Characteristics
844 char *dot;
845
846 /** @sketch
847 * Some parameter validations is probably useful.
848 */
849 if (!VALID_PSZ(lpszLibFile))
850 {
851 dprintf(("KERNEL32: LoadLibraryExA(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
852 lpszLibFile, hFile, dwFlags, lpszLibFile));
853 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
854 return NULL;
855 }
856 if (!VALID_PSZMAXSIZE(lpszLibFile, CCHMAXPATH))
857 {
858 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): lpszLibFile string too long, %d\n",
859 lpszLibFile, hFile, dwFlags, strlen(lpszLibFile)));
860 SetLastError(ERROR_INVALID_PARAMETER);
861 return NULL;
862 }
863 if ((dwFlags & ~(DONT_RESOLVE_DLL_REFERENCES | LOAD_WITH_ALTERED_SEARCH_PATH | LOAD_LIBRARY_AS_DATAFILE)) != 0)
864 {
865 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): dwFlags have invalid or unsupported flags\n",
866 lpszLibFile, hFile, dwFlags));
867 SetLastError(ERROR_INVALID_PARAMETER);
868 return NULL;
869 }
870
871 /** @sketch
872 * First we'll see if the module is allready loaded - either as the EXE or as DLL.
873 * IF Executable present AND libfile matches the modname of the executable THEN
874 * RETURN instance handle of executable.
875 * Endif
876 * IF allready loaded THEN
877 * IF it's a LX dll which isn't loaded and we're using the PeLoader THEN
878 * Set Load library.
879 * Endif
880 * Inc dynamic reference count.
881 * Inc reference count.
882 * RETURN instance handle.
883 * Endif
884 */
885 strcpy(szModname, lpszLibFile);
886 strupr(szModname);
887 dot = strchr(szModname, '.');
888 if(dot == NULL) {
889 //if there's no extension or trainling dot, we
890 //assume it's a dll (see Win32 SDK docs)
891 strcat(szModname, DLL_EXTENSION);
892 }
893 else {
894 if(dot[1] == 0) {
895 //a trailing dot means the module has no extension (SDK docs)
896 *dot = 0;
897 }
898 }
899 if (WinExe != NULL && WinExe->matchModName(szModname))
900 return WinExe->getInstanceHandle();
901
902 pModule = Win32DllBase::findModule((LPSTR)szModname);
903 if (pModule)
904 {
905 pModule->incDynamicLib();
906 pModule->AddRef();
907 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Dll found %s",
908 szModname, hFile, dwFlags, pModule->getInstanceHandle(), pModule->getFullPath()));
909 return pModule->getInstanceHandle();
910 }
911
912
913 /** @sketch
914 * Test if lpszLibFile has a path or not.
915 * Copy the lpszLibFile to szModname, rename the dll and uppercase the name.
916 * IF it hasn't a path THEN
917 * Issue a findDll to find the dll/executable to be loaded.
918 * IF the Dll isn't found THEN
919 * Set last error and RETURN.
920 * Endif.
921 * Endif
922 */
923 fPath = strchr(szModname, '\\') || strchr(szModname, '/');
924 Win32DllBase::renameDll(szModname);
925
926 if (!fPath)
927 {
928 char szModName2[CCHMAXPATH];
929 strcpy(szModName2, szModname);
930 if (!Win32ImageBase::findDll(szModName2, szModname, sizeof(szModname)))
931 {
932 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): module wasn't found. returns NULL",
933 lpszLibFile, hFile, dwFlags));
934 SetLastError(ERROR_FILE_NOT_FOUND);
935 return NULL;
936 }
937 }
938
939 //test if dll is in PE or LX format
940 fPE = Win32ImageBase::isPEImage(szModname, &Characteristics, NULL);
941
942 /** @sketch
943 * IF (fDisableLXDllLoading && (!fPeLoader || fPE == failure)) THEN
944 * Try load the executable using LoadLibrary
945 * IF successfully loaded THEN
946 * IF LX dll and is using the PE Loader THEN
947 * Set Load library.
948 * Inc reference count.
949 * Endif
950 * Inc dynamic reference count.
951 * RETURN successfully.
952 * Endif
953 * Endif
954 */
955 //only call OS/2 if LX binary or win32k process
956 if (!fDisableLXDllLoading && (!fPeLoader || fPE != ERROR_SUCCESS))
957 {
958 hDll = OSLibDosLoadModule(szModname);
959 if (hDll)
960 {
961 /* OS/2 dll, system dll, converted dll or win32k took care of it. */
962 pModule = Win32DllBase::findModuleByOS2Handle(hDll);
963 if (pModule)
964 {
965 if (pModule->isLxDll())
966 {
967 ((Win32LxDll *)pModule)->setDllHandleOS2(hDll);
968 if (fPeLoader && pModule->AddRef() == -1)
969 { //-1 -> load failed (attachProcess)
970 delete pModule;
971 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
972 dprintf(("Dll %s refused to be loaded; aborting", szModname));
973 return 0;
974 }
975
976 }
977 pModule->incDynamicLib();
978 }
979 else if (fExeStarted && !fIsOS2Image) {
980 OSLibDosFreeModule(hDll);
981 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
982 dprintf(("Dll %s is not an Odin dll; unload & return failure", szModname));
983 return 0;
984 }
985 else {
986 /* bird 2001-07-10:
987 * let's fail right away instead of hitting DebugInt3s and fail other places.
988 * This is very annoying when running Opera on a debug build with netscape/2
989 * plugins present. We'll make this conditional for the time being.
990 */
991 static BOOL fFailIfUnregisteredLX = -1;
992 if (fFailIfUnregisteredLX == -1)
993 fFailIfUnregisteredLX = getenv("ODIN32.FAIL_IF_UNREGISTEREDLX") != NULL;
994 if (fExeStarted && fFailIfUnregisteredLX)
995 {
996 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Loaded OS/2 dll %s using DosLoadModule. returns NULL.",
997 lpszLibFile, hFile, dwFlags, hDll, szModname));
998 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
999 return NULL;
1000 }
1001 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Loaded OS/2 dll %s using DosLoadModule.",
1002 lpszLibFile, hFile, dwFlags, hDll, szModname));
1003 return hDll; //happens when LoadLibrary is called in kernel32's initterm (nor harmful)
1004 }
1005 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): returns 0x%x. Loaded %s using DosLoadModule.",
1006 lpszLibFile, hFile, dwFlags, hDll, szModname));
1007 return pModule->getInstanceHandle();
1008 }
1009 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): DosLoadModule (%s) failed. LastError=%d",
1010 lpszLibFile, hFile, dwFlags, szModname, GetLastError()));
1011 }
1012 else
1013 hDll = NULL;
1014
1015
1016 /** @sketch
1017 * If PE image THEN
1018 * IF LOAD_LIBRARY_AS_DATAFILE or Executable THEN
1019 *
1020 *
1021 * Try load the file using the Win32PeLdrDll class.
1022 * <sketch continued further down>
1023 * Else
1024 * Set last error.
1025 * (hDll is NULL)
1026 * Endif
1027 * return hDll.
1028 */
1029 if(fPE == ERROR_SUCCESS)
1030 {
1031 Win32PeLdrDll *peldrDll;
1032
1033 //SvL: If executable -> load as data file (only resources)
1034 if(!(Characteristics & IMAGE_FILE_DLL))
1035 {
1036 dwFlags |= (LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES);
1037 }
1038
1039 peldrDll = new Win32PeLdrDll(szModname);
1040 if (peldrDll == NULL)
1041 {
1042 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Failed to created instance of Win32PeLdrDll. returns NULL.",
1043 lpszLibFile, hFile, dwFlags));
1044 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1045 return NULL;
1046 }
1047
1048 /** @sketch
1049 * Process dwFlags
1050 */
1051 if (dwFlags & LOAD_LIBRARY_AS_DATAFILE)
1052 {
1053 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): LOAD_LIBRARY_AS_DATAFILE",
1054 lpszLibFile, hFile, dwFlags));
1055 peldrDll->setLoadAsDataFile();
1056 peldrDll->disableLibraryCalls();
1057 }
1058 if (dwFlags & DONT_RESOLVE_DLL_REFERENCES)
1059 {
1060 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): DONT_RESOLVE_DLL_REFERENCES",
1061 lpszLibFile, hFile, dwFlags));
1062 peldrDll->disableLibraryCalls();
1063 peldrDll->disableImportHandling();
1064 }
1065 if (dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH)
1066 {
1067 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Warning dwFlags LOAD_WITH_ALTERED_SEARCH_PATH is not implemented.",
1068 lpszLibFile, hFile, dwFlags));
1069 //peldrDll->setLoadWithAlteredSearchPath();
1070 }
1071
1072 /** @sketch
1073 * Initiate the peldr DLL.
1074 * IF successful init THEN
1075 * Inc dynamic ref count.
1076 * Inc ref count.
1077 * Attach to process
1078 * IF successful THEN
1079 * hDLL <- instance handle.
1080 * ELSE
1081 * set last error
1082 * delete Win32PeLdrDll instance.
1083 * Endif
1084 * ELSE
1085 * set last error
1086 * delete Win32PeLdrDll instance.
1087 * Endif.
1088 */
1089 if(peldrDll->init(0) == LDRERROR_SUCCESS)
1090 {
1091 peldrDll->AddRef();
1092 if (peldrDll->attachProcess())
1093 {
1094 hDll = peldrDll->getInstanceHandle();
1095 //Must be called *after* attachprocess, since attachprocess may also
1096 //trigger LoadLibrary calls
1097 //Those dlls must not be put in front of this dll in the dynamic
1098 //dll list; or else the unload order is wrong:
1099 //i.e. RPAP3260 loads PNRS3260 in DLL_PROCESS_ATTACH
1100 // this means that in ExitProcess, PNRS3260 needs to be removed
1101 // first since RPAP3260 depends on it
1102 peldrDll->incDynamicLib();
1103 }
1104 else
1105 {
1106 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): attachProcess call to Win32PeLdrDll instance failed. returns NULL.",
1107 lpszLibFile, hFile, dwFlags));
1108 SetLastError(ERROR_DLL_INIT_FAILED);
1109 delete peldrDll;
1110 return NULL;
1111 }
1112 }
1113 else
1114 {
1115 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x): Failed to init Win32PeLdrDll instance. error=%d returns NULL.",
1116 lpszLibFile, hFile, dwFlags, peldrDll->getError()));
1117 SetLastError(ERROR_INVALID_EXE_SIGNATURE);
1118 delete peldrDll;
1119 return NULL;
1120 }
1121 }
1122 else
1123 {
1124 dprintf(("KERNEL32: LoadLibraryExA(%s, 0x%x, 0x%x) library wasn't found (%s) or isn't loadable; err %x",
1125 lpszLibFile, hFile, dwFlags, szModname, fPE));
1126 SetLastError(fPE);
1127 return NULL;
1128 }
1129
1130 return hDll;
1131}
1132
1133
1134/**
1135 * LoadLibraryExW can be used to map a DLL module into the calling process's
1136 * addressspace. It returns a handle that can be used with GetProcAddress to
1137 * get addresses of exported entry points (functions and variables).
1138 *
1139 * LoadLibraryExW can also be used to map executable (.exe) modules into the
1140 * address to access resources in the module. However, LoadLibrary can't be
1141 * used to run an executable (.exe) module.
1142 *
1143 * @returns Handle to the library which was loaded.
1144 * @param lpszLibFile Pointer to Unicode string giving the name of
1145 * the executable image (either a Dll or an Exe) which is to
1146 * be loaded.
1147 *
1148 * If no extention is specified the default .DLL extention is
1149 * appended to the name. End the filename with an '.' if the
1150 * file does not have an extention (and don't want the .DLL
1151 * appended).
1152 *
1153 * If no path is specified, this API will use the Odin32
1154 * standard search strategy to find the file. This strategy
1155 * is described in the method Win32ImageBase::findDLL.
1156 * This may be alterned by the LOAD_WITH_ALTERED_SEARCH_PATH
1157 * flag, see below.
1158 *
1159 * This API likes to have backslashes (\), but will probably
1160 * accept forward slashes too. Win32 SDK docs says that it
1161 * should not contain forward slashes.
1162 *
1163 * Win32 SDK docs adds:
1164 * "The name specified is the file name of the module and
1165 * is not related to the name stored in the library module
1166 * itself, as specified by the LIBRARY keyword in the
1167 * module-definition (.def) file."
1168 *
1169 * @param hFile Reserved. Must be 0.
1170 *
1171 * @param dwFlags Flags which specifies the taken when loading the module.
1172 * The value 0 makes it identical to LoadLibraryA/W.
1173 *
1174 * Flags:
1175 *
1176 * DONT_RESOLVE_DLL_REFERENCES
1177 * (WinNT/2K feature): Don't load imported modules and
1178 * hence don't resolve imported symbols.
1179 * DllMain isn't called either. (Which is obvious since
1180 * it may use one of the importe symbols.)
1181 *
1182 * On the other hand, if this flag is NOT set, the system
1183 * load imported modules, resolves imported symbols, calls
1184 * DllMain for process and thread init and term (if wished
1185 * by the module).
1186 *
1187 * LOAD_LIBRARY_AS_DATAFILE
1188 * If this flag is set, the module is mapped into the
1189 * address space but is not prepared for execution. Though
1190 * it's preparted for resource API. Hence, you'll use this
1191 * flag when you want to load a DLL for extracting
1192 * messages or resources from it.
1193 *
1194 * The resulting handle can be used with any Odin32 API
1195 * which operates on resources.
1196 * (WinNt/2k supports all resource APIs while Win9x don't
1197 * support the specialized resource APIs: LoadBitmap,
1198 * LoadCursor, LoadIcon, LoadImage, LoadMenu.)
1199 *
1200 * LOAD_WITH_ALTERED_SEARCH_PATH
1201 * If this flag is set and lpszLibFile specifies a path
1202 * we'll use an alternative file search strategy to find
1203 * imported modules. This stratgy is simply to use the
1204 * path of the module being loaded instead of the path
1205 * of the executable module as the first location
1206 * to search for imported modules.
1207 *
1208 * If this flag is clear, the standard Odin32 standard
1209 * search strategy. See Win32ImageBase::findDll for
1210 * further information.
1211 *
1212 * @sketch Convert Unicode name to ascii.
1213 * Call LoadLibraryExA.
1214 * Free ascii string.
1215 * return handle from LoadLibraryExA.
1216 * @status Open32 Partially Implemented.
1217 * @author Sander van Leeuwen (sandervl@xs4all.nl)
1218 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
1219 * @remark Forwards to LoadLibraryExA.
1220 */
1221HINSTANCE WIN32API LoadLibraryExW(LPCWSTR lpszLibFile, HANDLE hFile, DWORD dwFlags)
1222{
1223 char * pszAsciiLibFile;
1224 HINSTANCE hDll;
1225
1226 pszAsciiLibFile = UnicodeToAsciiString(lpszLibFile);
1227 dprintf(("KERNEL32: LoadLibraryExW(%s, 0x%x, 0x%x) --> LoadLibraryExA",
1228 pszAsciiLibFile, hFile, dwFlags));
1229 hDll = LoadLibraryExA(pszAsciiLibFile, hFile, dwFlags);
1230 dprintf(("KERNEL32: LoadLibraryExW(%s, 0x%x, 0x%x) returns 0x%x",
1231 pszAsciiLibFile, hFile, dwFlags, hDll));
1232 FreeAsciiString(pszAsciiLibFile);
1233
1234 return hDll;
1235}
1236//******************************************************************************
1237//******************************************************************************
1238HINSTANCE16 WIN32API LoadLibrary16(LPCTSTR lpszLibFile)
1239{
1240 dprintf(("ERROR: LoadLibrary16 %s, not implemented", lpszLibFile));
1241 return 0;
1242}
1243//******************************************************************************
1244//******************************************************************************
1245VOID WIN32API FreeLibrary16(HINSTANCE16 hinstance)
1246{
1247 dprintf(("ERROR: FreeLibrary16 %x, not implemented", hinstance));
1248}
1249//******************************************************************************
1250//******************************************************************************
1251FARPROC WIN32API GetProcAddress16(HMODULE hModule, LPCSTR lpszProc)
1252{
1253 dprintf(("ERROR: GetProcAddress16 %x %x, not implemented", hModule, lpszProc));
1254 return 0;
1255}
1256
1257
1258/**
1259 * Internal function which gets the commandline (string) used to start the current process.
1260 * @returns OS/2 / Windows return code
1261 * On successful return (NO_ERROR) the global variables
1262 * pszCmdLineA and pszCmdLineW are set.
1263 *
1264 * @param pszPeExe Pass in the name of the PE exe of this process. We'll
1265 * us this as exename and skip the first argument (ie. argv[1]).
1266 * If NULL we'll use the commandline from OS/2 as it is.
1267 * @status Completely implemented and tested.
1268 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1269 */
1270ULONG InitCommandLine(const char *pszPeExe)
1271{
1272 PCHAR pib_pchcmd; /* PIB pointer to commandline. */
1273 CHAR szFilename[CCHMAXPATH]; /* Filename buffer used to get the exe filename in. */
1274 ULONG cch; /* Commandline string length. (including terminator) */
1275 PSZ psz; /* Temporary string pointer. */
1276 PSZ psz2; /* Temporary string pointer. */
1277 APIRET rc; /* OS/2 return code. */
1278 BOOL fQuotes; /* Flag used to remember if the exe filename should be in quotes. */
1279
1280 /** @sketch
1281 * Get commandline from the PIB.
1282 */
1283 pib_pchcmd = (PCHAR)OSLibGetPIB(PIB_PCHCMD);
1284
1285 /** @sketch
1286 * Two methods of making the commandline:
1287 * (1) The first argument is skipped and the second is used as exe filname.
1288 * This applies to PE.EXE launched processes only.
1289 * (2) No skipping. First argument is the exe filename.
1290 * This applies to all but PE.EXE launched processes.
1291 *
1292 * Note: We could do some code size optimization here. Much of the code for
1293 * the two methods are nearly identical.
1294 *
1295 */
1296 if(pszPeExe)
1297 {
1298 /** @sketch
1299 * Allocate memory for the commandline.
1300 * Build commandline:
1301 * Copy exe filename.
1302 * Add arguments.
1303 */
1304 cch = strlen(pszPeExe)+1;
1305
1306 // PH 2002-04-11
1307 // Note: intentional memory leak, pszCmdLineW will not be freed
1308 // or allocated after process startup
1309 pszCmdLineA = psz = (PSZ)malloc(cch);
1310 if (psz == NULL)
1311 {
1312 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed\n", pszPeExe, cch));
1313 return ERROR_NOT_ENOUGH_MEMORY;
1314 }
1315 strcpy((char *)pszCmdLineA, pszPeExe);
1316
1317 rc = NO_ERROR;
1318 }
1319 else
1320 {
1321 /** @sketch Method (2):
1322 * First we'll have to determin the size of the commandline.
1323 *
1324 * As we don't assume that OS/2 allways puts a fully qualified EXE name
1325 * as the first string, we'll check if it's empty - and get the modulename
1326 * in that case - and allways get the fully qualified filename.
1327 */
1328 if (pib_pchcmd == NULL || pib_pchcmd[0] == '\0')
1329 {
1330 rc = OSLibDosQueryModuleName(OSLibGetPIB(PIB_HMTE), sizeof(szFilename), szFilename);
1331 if (rc != NO_ERROR)
1332 {
1333 dprintf(("KERNEL32: InitCommandLine(%p): OSLibQueryModuleName(0x%x,...) failed with rc=%d\n",
1334 pszPeExe, OSLibGetPIB(PIB_HMTE), rc));
1335 return rc;
1336 }
1337 }
1338 else
1339 {
1340 rc = OSLibDosQueryPathInfo(pib_pchcmd, FIL_QUERYFULLNAME, szFilename, sizeof(szFilename));
1341 if (rc != NO_ERROR)
1342 {
1343 dprintf(("KERNEL32: InitCommandLine(%p): (info) OSLibDosQueryPathInfo failed with rc=%d\n", pszPeExe, rc));
1344 strcpy(szFilename, pib_pchcmd);
1345 rc = NO_ERROR;
1346 }
1347 }
1348
1349 /** @sketch
1350 * We're still measuring the size of the commandline:
1351 * Check if we have to quote the exe filename.
1352 * Determin the length of the executable name including quotes and '\0'-terminator.
1353 * Count the length of the arguments. (We here count's all argument strings.)
1354 */
1355 fQuotes = strchr(szFilename, ' ') != NULL;
1356 cch = strlen(szFilename) + fQuotes*2 + 1;
1357 if (pib_pchcmd != NULL)
1358 {
1359 psz2 = pib_pchcmd + strlen(pib_pchcmd) + 1;
1360 while (*psz2 != '\0')
1361 {
1362 register int cchTmp = strlen(psz2) + 1; /* + 1 is for terminator (psz2) and space (cch). */
1363 psz2 += cchTmp;
1364 cch += cchTmp;
1365 }
1366 }
1367
1368 /** @sketch
1369 * Allocate memory for the commandline.
1370 * Build commandline:
1371 * Copy exe filename.
1372 * Add arguments.
1373 */
1374 pszCmdLineA = psz = (PSZ)malloc(cch);
1375 if (psz == NULL)
1376 {
1377 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed\n", pszPeExe, cch));
1378 return ERROR_NOT_ENOUGH_MEMORY;
1379 }
1380
1381 if (fQuotes)
1382 *psz++ = '"';
1383 strcpy(psz, szFilename);
1384 psz += strlen(psz);
1385 if (fQuotes)
1386 {
1387 *psz++ = '"';
1388 *psz = '\0';
1389 }
1390
1391 if (pib_pchcmd != NULL)
1392 {
1393 psz2 = pib_pchcmd + strlen(pib_pchcmd) + 1;
1394 while (*psz2 != '\0')
1395 {
1396 register int cchTmp = strlen(psz2) + 1; /* + 1 is for terminator (psz). */
1397 *psz++ = ' '; /* add space */
1398 memcpy(psz, psz2, cchTmp);
1399 psz2 += cchTmp;
1400 psz += cchTmp - 1;
1401 }
1402 }
1403 }
1404
1405 /** @sketch
1406 * If successfully build ASCII commandline then convert it to UniCode.
1407 */
1408 if (rc == NO_ERROR)
1409 {
1410 // PH 2002-04-11
1411 // Note: intentional memory leak, pszCmdLineW will not be freed
1412 // or allocated after process startup
1413 cch = strlen(pszCmdLineA) + 1;
1414
1415 pszCmdLineW = (WCHAR*)malloc(cch * 2);
1416 if (pszCmdLineW != NULL) {
1417 //Translate from OS/2 to Windows codepage & ascii to unicode
1418 MultiByteToWideChar(CP_OEMCP, 0, pszCmdLineA, -1, (LPWSTR)pszCmdLineW, cch-1);
1419 ((LPWSTR)pszCmdLineW)[cch-1] = 0;
1420
1421 //ascii command line is still in OS/2 codepage, so convert it
1422 WideCharToMultiByte(CP_ACP, 0, pszCmdLineW, -1, (LPSTR)pszCmdLineA, cch-1, 0, NULL);
1423 ((LPSTR)pszCmdLineA)[cch-1] = 0;
1424 }
1425 else
1426 {
1427 DebugInt3();
1428 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed (2)\n", pszPeExe, cch));
1429 rc = ERROR_NOT_ENOUGH_MEMORY;
1430 }
1431 }
1432
1433 return rc;
1434}
1435
1436/**
1437 * Gets the command line of the current process.
1438 * @returns On success:
1439 * Command line of the current process. One single string.
1440 * The first part of the command line string is the executable filename
1441 * of the current process. It might be in quotes if it contains spaces.
1442 * The rest of the string is arguments.
1443 *
1444 * On error:
1445 * NULL. Last error set. (does Win32 set last error this?)
1446 * @sketch IF not inited THEN
1447 * Init commandline assuming !PE.EXE
1448 * IF init failes THEN set last error.
1449 * ENDIF
1450 * return ASCII/ANSI commandline.
1451 * @status Completely implemented and tested.
1452 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1453 * @remark The Ring-3 PeLdr is resposible for calling InitCommandLine before anyone
1454 * is able to call this function.
1455 */
1456LPCSTR WIN32API GetCommandLineA(VOID)
1457{
1458 /*
1459 * Check if the commandline is initiated.
1460 * If not we'll have to do it.
1461 * ASSUMES that if not inited this isn't a PE.EXE lauched process.
1462 */
1463 if (pszCmdLineA == NULL)
1464 {
1465 APIRET rc;
1466 rc = InitCommandLine(NULL);
1467 if (rc != NULL)
1468 SetLastError(rc);
1469 }
1470
1471 dprintf(("KERNEL32: GetCommandLineA: %s\n", pszCmdLineA));
1472 return pszCmdLineA;
1473}
1474
1475
1476/**
1477 * Gets the command line of the current process.
1478 * @returns On success:
1479 * Command line of the current process. One single string.
1480 * The first part of the command line string is the executable filename
1481 * of the current process. It might be in quotes if it contains spaces.
1482 * The rest of the string is arguments.
1483 *
1484 * On error:
1485 * NULL. Last error set. (does Win32 set last error this?)
1486 * @sketch IF not inited THEN
1487 * Init commandline assuming !PE.EXE
1488 * IF init failes THEN set last error.
1489 * ENDIF
1490 * return Unicode commandline.
1491 * @status Completely implemented and tested.
1492 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1493 * @remark The Ring-3 PeLdr is resposible for calling InitCommandLine before anyone
1494 * is able to call this function.
1495 */
1496LPCWSTR WIN32API GetCommandLineW(void)
1497{
1498 /*
1499 * Check if the commandline is initiated.
1500 * If not we'll have to do it.
1501 * ASSUMES that if not inited this isn't a PE.EXE lauched process.
1502 */
1503 if (pszCmdLineW == NULL)
1504 {
1505 APIRET rc;
1506 rc = InitCommandLine(NULL);
1507 if (rc != NULL)
1508 SetLastError(rc);
1509 }
1510
1511 dprintf(("KERNEL32: GetCommandLineW: %s\n", pszCmdLineA));
1512 return pszCmdLineW;
1513}
1514
1515
1516/**
1517 * GetModuleFileName gets the full path and file name for the specified module.
1518 * @returns Bytes written to the buffer (lpszPath). This count includes the
1519 * terminating '\0'.
1520 * On error 0 is returned. Last error is set.
1521 *
1522 * 2002-04-25 PH
1523 * Q - Do we set ERROR_BUFFER_OVERFLOW when cch > cchPath?
1524 * Q - Does NT really set the last error?
1525 * A > Win2k does not set LastError here, remains OK
1526 *
1527 * While GetModuleFileName does add a trailing termination zero
1528 * if there is enough room, the returned number of characters
1529 * *MUST NOT* include the zero character!
1530 * (Notes R6 Installer on Win2kSP6, verified Testcase)
1531 *
1532 * @param hModule Handle to the module you like to get the file name to.
1533 * @param lpszPath Output buffer for full path and file name.
1534 * @param cchPath Size of the lpszPath buffer.
1535 * @sketch Validate lpszPath.
1536 * Find the module object using handle.
1537 * If found Then
1538 * Get full path from module object.
1539 * If found path Then
1540 * Copy path to buffer and set the number of bytes written.
1541 * Else
1542 * IPE!
1543 * Else
1544 * Call Open32 GetModuleFileName. (kernel32 initterm needs/needed this)
1545 * Log result.
1546 * Return number of bytes written to the buffer.
1547 *
1548 * @status Completely implemented, Open32.
1549 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1550 * Sander van Leeuwen (sandervl@xs4all.nl)
1551 * Patrick Haller (patrick.haller@innotek.de)
1552 * @remark - Do we still have to call Open32?
1553 */
1554DWORD WIN32API GetModuleFileNameA(HMODULE hModule, LPTSTR lpszPath, DWORD cchPath)
1555{
1556 Win32ImageBase * pMod; /* Pointer to the module object. */
1557 DWORD cch = 0; /* Length of the */
1558
1559 // PH 2002-04-24 Note:
1560 // WIN2k just crashes in NTDLL if lpszPath is invalid!
1561 if (!VALID_PSZ(lpszPath))
1562 {
1563 dprintf(("KERNEL32: GetModuleFileNameA(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
1564 hModule, lpszPath, cchPath, lpszPath));
1565 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
1566 return 0;
1567 }
1568
1569 pMod = Win32ImageBase::findModule(hModule);
1570 if (pMod != NULL)
1571 {
1572 const char *pszFn = pMod->getFullPath();
1573 if (pszFn)
1574 {
1575 cch = strlen(pszFn);
1576 if (cch >= cchPath)
1577 cch = cchPath;
1578 else
1579 // if there is sufficient room for the zero termination,
1580 // write it additionally, uncounted
1581 lpszPath[cch] = '\0';
1582
1583 memcpy(lpszPath, pszFn, cch);
1584 }
1585 else
1586 {
1587 dprintf(("KERNEL32: GetModuleFileNameA(%x,...): IPE - getFullPath returned NULL or empty string\n"));
1588 DebugInt3();
1589 SetLastError(ERROR_INVALID_HANDLE);
1590 }
1591 }
1592 else
1593 {
1594 SetLastError(ERROR_INVALID_HANDLE);
1595 //only needed for call inside kernel32's initterm (profile init)
1596 //(console init only it seems...)
1597 cch = OSLibDosGetModuleFileName(hModule, lpszPath, cchPath);
1598 }
1599
1600 if (cch > 0)
1601 dprintf(("KERNEL32: GetModuleFileNameA(%x %x): %s %d\n", hModule, lpszPath, lpszPath, cch));
1602 else
1603 dprintf(("KERNEL32: WARNING: GetModuleFileNameA(%x,...) - not found!", hModule));
1604
1605 return cch;
1606}
1607
1608
1609/**
1610 * GetModuleFileName gets the full path and file name for the specified module.
1611 * @returns Bytes written to the buffer (lpszPath). This count includes the
1612 * terminating '\0'.
1613 * On error 0 is returned. Last error is set.
1614 * @param hModule Handle to the module you like to get the file name to.
1615 * @param lpszPath Output buffer for full path and file name.
1616 * @param cchPath Size of the lpszPath buffer.
1617 * @sketch Find the module object using handle.
1618 * If found Then
1619 * get full path from module object.
1620 * If found path Then
1621 * Determin path length.
1622 * Translate the path to into the buffer.
1623 * Else
1624 * IPE.
1625 * else
1626 * SetLastError to invalid handle.
1627 * Log result.
1628 * return number of bytes written to the buffer.
1629 *
1630 * @status Completely implemented.
1631 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1632 * @remark - We do _NOT_ call Open32.
1633 * - Do we set ERROR_BUFFER_OVERFLOW when cch > cchPath?
1634 * - Does NT really set the last error?
1635 */
1636DWORD WIN32API GetModuleFileNameW(HMODULE hModule, LPWSTR lpszPath, DWORD cchPath)
1637{
1638 Win32ImageBase * pMod;
1639 DWORD cch = 0;
1640
1641 if (!VALID_PSZ(lpszPath))
1642 {
1643 dprintf(("KERNEL32: GetModuleFileNameW(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
1644 hModule, lpszPath, cchPath, lpszPath));
1645 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
1646 return 0;
1647 }
1648
1649 pMod = Win32ImageBase::findModule(hModule);
1650 if (pMod != NULL)
1651 {
1652 const char *pszFn = pMod->getFullPath();
1653 if (pszFn || *pszFn != '\0')
1654 {
1655 cch = strlen(pszFn) + 1;
1656 if (cch > cchPath)
1657 cch = cchPath;
1658 AsciiToUnicodeN(pszFn, lpszPath, cch);
1659 }
1660 else
1661 {
1662 dprintf(("KERNEL32: GetModuleFileNameW(%x,...): IPE - getFullPath returned NULL or empty string\n"));
1663 DebugInt3();
1664 SetLastError(ERROR_INVALID_HANDLE);
1665 }
1666 }
1667 else
1668 SetLastError(ERROR_INVALID_HANDLE);
1669
1670 if (cch > 0)
1671 dprintf(("KERNEL32: GetModuleFileNameW(%x,...): %s %d\n", hModule, lpszPath, cch));
1672 else
1673 dprintf(("KERNEL32: WARNING: GetModuleFileNameW(%x,...) - not found!", hModule));
1674
1675 return cch;
1676}
1677
1678
1679//******************************************************************************
1680//NOTE: GetModuleHandleA does NOT support files with multiple dots (i.e.
1681// very.weird.exe)
1682//
1683// hinst = LoadLibrary("WINSPOOL.DRV"); -> succeeds
1684// hinst2 = GetModuleHandle("WINSPOOL.DRV"); -> succeeds
1685// hinst3 = GetModuleHandle("WINSPOOL."); -> fails
1686// hinst4 = GetModuleHandle("WINSPOOL"); -> fails
1687// hinst = LoadLibrary("KERNEL32.DLL"); -> succeeds
1688// hinst2 = GetModuleHandle("KERNEL32.DLL"); -> succeeds
1689// hinst3 = GetModuleHandle("KERNEL32."); -> fails
1690// hinst4 = GetModuleHandle("KERNEL32"); -> succeeds
1691// Same behaviour as observed in NT4, SP6
1692//******************************************************************************
1693HANDLE WIN32API GetModuleHandleA(LPCTSTR lpszModule)
1694{
1695 HANDLE hMod = 0;
1696 Win32DllBase *windll;
1697 char szModule[CCHMAXPATH];
1698 char *dot;
1699
1700 if(lpszModule == NULL)
1701 {
1702 if(WinExe)
1703 hMod = WinExe->getInstanceHandle();
1704 else
1705 {
1706 // // Just fail this API
1707 // hMod = 0;
1708 // SetLastError(ERROR_INVALID_HANDLE);
1709 // Wrong: in an ODIN32-LX environment, just
1710 // assume a fake handle
1711 hMod = -1;
1712 }
1713 }
1714 else
1715 {
1716 strcpy(szModule, OSLibStripPath((char *)lpszModule));
1717 strupr(szModule);
1718 dot = strchr(szModule, '.');
1719 if(dot == NULL) {
1720 //if no extension -> add .DLL (see SDK docs)
1721 strcat(szModule, DLL_EXTENSION);
1722 }
1723 else {
1724 if(dot[1] == 0) {
1725 //a trailing dot means the module has no extension (SDK docs)
1726 *dot = 0;
1727 }
1728 }
1729 if(WinExe && WinExe->matchModName(szModule)) {
1730 hMod = WinExe->getInstanceHandle();
1731 }
1732 else {
1733 windll = Win32DllBase::findModule(szModule);
1734 if(windll) {
1735 hMod = windll->getInstanceHandle();
1736 }
1737 }
1738 }
1739 dprintf(("KERNEL32: GetModuleHandle %s returned %X\n", lpszModule, hMod));
1740 return(hMod);
1741}
1742//******************************************************************************
1743//******************************************************************************
1744HMODULE WIN32API GetModuleHandleW(LPCWSTR lpwszModuleName)
1745{
1746 HMODULE rc;
1747 char *astring = NULL;
1748
1749 if (NULL != lpwszModuleName)
1750 astring = UnicodeToAsciiString((LPWSTR)lpwszModuleName);
1751
1752 rc = GetModuleHandleA(astring);
1753 dprintf(("KERNEL32: OS2GetModuleHandleW %s returned %X\n", astring, rc));
1754
1755 if (NULL != astring)
1756 FreeAsciiString(astring);
1757
1758 return(rc);
1759}
1760//******************************************************************************
1761//******************************************************************************
1762static char szPECmdLoader[260] = "";
1763static char szPEGUILoader[260] = "";
1764static char szNELoader[260] = "";
1765//******************************************************************************
1766//Set default paths for PE & NE loaders
1767//******************************************************************************
1768BOOL InitLoaders()
1769{
1770 sprintf(szPECmdLoader, "%s\\PEC.EXE", InternalGetSystemDirectoryA());
1771 sprintf(szPEGUILoader, "%s\\PE.EXE", InternalGetSystemDirectoryA());
1772 sprintf(szNELoader, "%s\\W16ODIN.EXE", InternalGetSystemDirectoryA());
1773
1774 return TRUE;
1775}
1776//******************************************************************************
1777//Override loader names (PEC, PE, W16ODIN)
1778//******************************************************************************
1779BOOL WIN32API ODIN_SetLoaders(LPCSTR pszPECmdLoader, LPCSTR pszPEGUILoader,
1780 LPCSTR pszNELoader)
1781{
1782 if(pszPECmdLoader) strcpy(szPECmdLoader, pszPECmdLoader);
1783 if(pszPEGUILoader) strcpy(szPEGUILoader, pszPEGUILoader);
1784 if(pszNELoader) strcpy(szNELoader, pszNELoader);
1785
1786 return TRUE;
1787}
1788//******************************************************************************
1789//******************************************************************************
1790BOOL WIN32API ODIN_QueryLoaders(LPSTR pszPECmdLoader, INT cchPECmdLoader,
1791 LPSTR pszPEGUILoader, INT cchPEGUILoader,
1792 LPSTR pszNELoader, INT cchNELoader)
1793{
1794 if(pszPECmdLoader) strncpy(pszPECmdLoader, szPECmdLoader, cchPECmdLoader);
1795 if(pszPEGUILoader) strncpy(pszPEGUILoader, szPEGUILoader, cchPEGUILoader);
1796 if(pszNELoader) strncpy(pszNELoader, szNELoader, cchNELoader);
1797
1798 return TRUE;
1799}
1800//******************************************************************************
1801//******************************************************************************
1802BOOL WINAPI CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine,
1803 LPSECURITY_ATTRIBUTES lpProcessAttributes,
1804 LPSECURITY_ATTRIBUTES lpThreadAttributes,
1805 BOOL bInheritHandles, DWORD dwCreationFlags,
1806 LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
1807 LPSTARTUPINFOA lpStartupInfo,
1808 LPPROCESS_INFORMATION lpProcessInfo )
1809{
1810 TEB *pThreadDB = (TEB*)GetThreadTEB();
1811 char *cmdline = NULL;
1812 BOOL rc;
1813
1814 dprintf(("KERNEL32: CreateProcessA %s cline:%s inherit:%d cFlags:%x Env:%x CurDir:%s StartupFlags:%x\n",
1815 lpApplicationName, lpCommandLine, bInheritHandles, dwCreationFlags,
1816 lpEnvironment, lpCurrentDirectory, lpStartupInfo));
1817
1818#ifdef DEBUG
1819 if(lpStartupInfo) {
1820 dprintf(("lpStartupInfo->lpReserved %x", lpStartupInfo->lpReserved));
1821 dprintf(("lpStartupInfo->lpDesktop %x", lpStartupInfo->lpDesktop));
1822 dprintf(("lpStartupInfo->lpTitle %s", lpStartupInfo->lpTitle));
1823 dprintf(("lpStartupInfo->dwX %x", lpStartupInfo->dwX));
1824 dprintf(("lpStartupInfo->dwY %x", lpStartupInfo->dwY));
1825 dprintf(("lpStartupInfo->dwXSize %x", lpStartupInfo->dwXSize));
1826 dprintf(("lpStartupInfo->dwYSize %x", lpStartupInfo->dwYSize));
1827 dprintf(("lpStartupInfo->dwXCountChars %x", lpStartupInfo->dwXCountChars));
1828 dprintf(("lpStartupInfo->dwYCountChars %x", lpStartupInfo->dwYCountChars));
1829 dprintf(("lpStartupInfo->dwFillAttribute %x", lpStartupInfo->dwFillAttribute));
1830 dprintf(("lpStartupInfo->dwFlags %x", lpStartupInfo->dwFlags));
1831 dprintf(("lpStartupInfo->wShowWindow %x", lpStartupInfo->wShowWindow));
1832 dprintf(("lpStartupInfo->hStdInput %x", lpStartupInfo->hStdInput));
1833 dprintf(("lpStartupInfo->hStdOutput %x", lpStartupInfo->hStdOutput));
1834 dprintf(("lpStartupInfo->hStdError %x", lpStartupInfo->hStdError));
1835 }
1836#endif
1837
1838 // open32 does not support DEBUG_ONLY_THIS_PROCESS
1839 if(dwCreationFlags & DEBUG_ONLY_THIS_PROCESS)
1840 dwCreationFlags |= DEBUG_PROCESS;
1841
1842 if(O32_CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes,
1843 lpThreadAttributes, bInheritHandles, dwCreationFlags,
1844 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
1845 lpProcessInfo) == TRUE)
1846 {
1847 if (dwCreationFlags & DEBUG_PROCESS && pThreadDB != NULL)
1848 {
1849 if(pThreadDB->o.odin.pidDebuggee != 0)
1850 {
1851 // TODO: handle this
1852 dprintf(("KERNEL32: CreateProcess ERROR: This thread is already a debugger\n"));
1853 }
1854 else
1855 {
1856 pThreadDB->o.odin.pidDebuggee = lpProcessInfo->dwProcessId;
1857 OSLibStartDebugger((ULONG*)&pThreadDB->o.odin.pidDebuggee);
1858 }
1859 }
1860 else pThreadDB->o.odin.pidDebuggee = 0;
1861
1862 return(TRUE);
1863 }
1864
1865 // PH 2001-05-07
1866 // verify why O32_CreateProcess actually failed.
1867 // If GetLastError() == 191 (ERROR_INVALID_EXE_SIGNATURE)
1868 // we can continue to call "PE.EXE".
1869 // Note: Open32 does not translate ERROR_INVALID_EXE_SIGNATURE,
1870 // it is also valid in Win32.
1871 DWORD dwError = GetLastError();
1872 if (ERROR_INVALID_EXE_SIGNATURE != dwError && ERROR_FILE_NOT_FOUND != dwError && ERROR_ACCESS_DENIED != dwError)
1873 {
1874 dprintf(("CreateProcess: O32_CreateProcess failed with rc=%d, not PE-executable !",
1875 dwError));
1876
1877 // the current value of GetLastError() is still valid.
1878
1879 return FALSE;
1880 }
1881
1882 // else ...
1883
1884 //probably a win32 exe, so run it in the pe loader
1885 if(lpApplicationName) {
1886 if(lpCommandLine) {
1887 //skip exe name in lpCommandLine
1888 //TODO: doesn't work for directories with spaces!
1889 while(*lpCommandLine != 0 && *lpCommandLine != ' ')
1890 lpCommandLine++;
1891
1892 if(*lpCommandLine != 0) {
1893 lpCommandLine++;
1894 }
1895 cmdline = (char *)malloc(strlen(lpApplicationName)+strlen(lpCommandLine) + 16);
1896 sprintf(cmdline, "%s %s", lpApplicationName, lpCommandLine);
1897 }
1898 else {
1899 cmdline = (char *)malloc(strlen(lpApplicationName) + 16);
1900 sprintf(cmdline, "%s", lpApplicationName);
1901 }
1902 }
1903 else {
1904 cmdline = (char *)malloc(strlen(lpCommandLine) + 16);
1905 sprintf(cmdline, "%s", lpCommandLine);
1906 }
1907
1908 char szAppName[MAX_PATH];
1909 char buffer[MAX_PATH];
1910 DWORD fileAttr;
1911 char *exename = buffer;
1912 strncpy(buffer, cmdline, sizeof(szAppName));
1913 buffer[MAX_PATH-1] = 0;
1914 if(*exename == '"') {
1915 exename++;
1916 while(*exename != 0 && *exename != '"')
1917 exename++;
1918
1919 if(*exename != 0) {
1920 *exename = 0;
1921 }
1922 exename++;
1923 if (SearchPathA( NULL, &buffer[1], ".exe", sizeof(szAppName), szAppName, NULL ) ||
1924 SearchPathA( NULL, &buffer[1], NULL, sizeof(szAppName), szAppName, NULL ))
1925 {
1926 //
1927 }
1928 }
1929 else {
1930 BOOL fTerminate = FALSE;
1931 DWORD fileAttr;
1932
1933 while(*exename != 0) {
1934 while(*exename != 0 && *exename != ' ')
1935 exename++;
1936
1937 if(*exename != 0) {
1938 *exename = 0;
1939 fTerminate = TRUE;
1940 }
1941 dprintf(("Trying '%s'", buffer ));
1942 if (SearchPathA( NULL, buffer, ".exe", sizeof(szAppName), szAppName, NULL ) ||
1943 SearchPathA( NULL, buffer, NULL, sizeof(szAppName), szAppName, NULL ))
1944 {
1945 if(fTerminate) exename++;
1946 break;
1947 }
1948
1949 if(fTerminate) {
1950 *exename = ' ';
1951 exename++;
1952 fTerminate = FALSE;
1953 }
1954 }
1955 }
1956 lpCommandLine = exename; //start of command line parameters
1957
1958 fileAttr = GetFileAttributesA(szAppName);
1959 if(fileAttr == -1 || (fileAttr & FILE_ATTRIBUTE_DIRECTORY)) {
1960 dprintf(("CreateProcess: can't find executable!"));
1961 SetLastError(ERROR_FILE_NOT_FOUND);
1962 return FALSE;
1963 }
1964
1965 dprintf(("KERNEL32: CreateProcess %s %s", szAppName, lpCommandLine));
1966
1967 DWORD Characteristics, SubSystem, fNEExe;
1968 if(Win32ImageBase::isPEImage(szAppName, &Characteristics, &SubSystem, &fNEExe) == 0)
1969 {
1970 char *lpszPE;
1971 char *lpszExecutable;
1972 int iNewCommandLineLength;
1973
1974 // calculate base length for the new command line
1975 iNewCommandLineLength = strlen(szAppName) + strlen(lpCommandLine);
1976
1977 if(SubSystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
1978 lpszExecutable = (LPSTR)szPECmdLoader;
1979 else
1980 lpszExecutable = (LPSTR)szPEGUILoader;
1981
1982 lpszPE = lpszExecutable;
1983
1984 // 2002-04-24 PH
1985 // set the ODIN32.DEBUG_CHILD environment variable to start new PE processes
1986 // under a new instance of the (IPMD) debugger.
1987#ifdef DEBUG
1988 CHAR debug_szPE[ 512 ];
1989 PSZ debug_pszOS2Debugger = getenv("ODIN32.DEBUG_CHILD");
1990 if (NULL != debug_pszOS2Debugger)
1991 {
1992 // build new start command
1993 strcpy(debug_szPE, debug_pszOS2Debugger);
1994 strcat(debug_szPE, " ");
1995 strcat(debug_szPE, lpszExecutable);
1996
1997 // we require more space in the new command line
1998 iNewCommandLineLength += strlen( debug_szPE );
1999
2000 // only launch the specified executable (ICSDEBUG.EXE)
2001 lpszPE = debug_szPE;
2002 lpszExecutable = debug_pszOS2Debugger;
2003 }
2004#endif
2005
2006 //SvL: Allright. Before we call O32_CreateProcess, we must take care of
2007 // lpCurrentDirectory ourselves. (Open32 ignores it!)
2008 if(lpCurrentDirectory) {
2009 char *newcmdline;
2010
2011 newcmdline = (char *)malloc(strlen(lpCurrentDirectory) + iNewCommandLineLength + strlen(lpszPE) + 16);
2012 sprintf(newcmdline, "%s /OPT:[CURDIR=%s] %s %s", lpszPE, lpCurrentDirectory, szAppName, lpCommandLine);
2013 free(cmdline);
2014 cmdline = newcmdline;
2015 }
2016 else {
2017 char *newcmdline;
2018
2019 newcmdline = (char *)malloc(iNewCommandLineLength + strlen(lpszPE) + 16);
2020 sprintf(newcmdline, "%s %s %s", lpszPE, szAppName, lpCommandLine);
2021 free(cmdline);
2022 cmdline = newcmdline;
2023 }
2024
2025 dprintf(("KERNEL32: CreateProcess starting [%s],[%s]",
2026 lpszExecutable,
2027 cmdline));
2028
2029 rc = O32_CreateProcess(lpszExecutable, (LPCSTR)cmdline,lpProcessAttributes,
2030 lpThreadAttributes, bInheritHandles, dwCreationFlags,
2031 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
2032 lpProcessInfo);
2033 }
2034 else
2035 if(fNEExe) {//16 bits windows app
2036 char *newcmdline;
2037
2038 newcmdline = (char *)malloc(strlen(szAppName) + strlen(cmdline) + strlen(szNELoader) + strlen(szPEGUILoader) + strlen(lpCommandLine) + 32);
2039
2040 sprintf(newcmdline, "%s /PELDR=[%s] %s", szNELoader, szPEGUILoader, szAppName, lpCommandLine);
2041 free(cmdline);
2042 cmdline = newcmdline;
2043 //Force Open32 to use DosStartSession (DosExecPgm won't do)
2044 dwCreationFlags |= CREATE_NEW_PROCESS_GROUP;
2045
2046 dprintf(("KERNEL32: CreateProcess starting [%s],[%s]",
2047 szNELoader,
2048 cmdline));
2049 rc = O32_CreateProcess(szNELoader, (LPCSTR)cmdline, lpProcessAttributes,
2050 lpThreadAttributes, bInheritHandles, dwCreationFlags,
2051 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
2052 lpProcessInfo);
2053 }
2054 else {//os/2 app??
2055 rc = O32_CreateProcess(szAppName, (LPCSTR)lpCommandLine, lpProcessAttributes,
2056 lpThreadAttributes, bInheritHandles, dwCreationFlags,
2057 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
2058 lpProcessInfo);
2059 }
2060 if(rc == TRUE)
2061 {
2062 if (dwCreationFlags & DEBUG_PROCESS && pThreadDB != NULL)
2063 {
2064 if(pThreadDB->o.odin.pidDebuggee != 0)
2065 {
2066 // TODO: handle this
2067 dprintf(("KERNEL32: CreateProcess ERROR: This thread is already a debugger\n"));
2068 }
2069 else
2070 {
2071 pThreadDB->o.odin.pidDebuggee = lpProcessInfo->dwProcessId;
2072 OSLibStartDebugger((ULONG*)&pThreadDB->o.odin.pidDebuggee);
2073 }
2074 }
2075 else
2076 pThreadDB->o.odin.pidDebuggee = 0;
2077 }
2078 if(cmdline)
2079 free(cmdline);
2080
2081 if(lpProcessInfo)
2082 {
2083 lpProcessInfo->dwThreadId = MAKE_THREADID(lpProcessInfo->dwProcessId, lpProcessInfo->dwThreadId);
2084 dprintf(("KERNEL32: CreateProcess returned %d hPro:%x hThr:%x pid:%x tid:%x\n",
2085 rc, lpProcessInfo->hProcess, lpProcessInfo->hThread,
2086 lpProcessInfo->dwProcessId,lpProcessInfo->dwThreadId));
2087 }
2088 else
2089 dprintf(("KERNEL32: CreateProcess returned %d\n", rc));
2090 return(rc);
2091}
2092//******************************************************************************
2093//******************************************************************************
2094BOOL WIN32API CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
2095 PSECURITY_ATTRIBUTES lpProcessAttributes,
2096 PSECURITY_ATTRIBUTES lpThreadAttributes,
2097 BOOL bInheritHandles, DWORD dwCreationFlags,
2098 LPVOID lpEnvironment,
2099 LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
2100 LPPROCESS_INFORMATION lpProcessInfo)
2101{
2102 BOOL rc;
2103 char *astring1 = 0, *astring2 = 0, *astring3 = 0;
2104
2105 dprintf(("KERNEL32: CreateProcessW"));
2106 if(lpApplicationName)
2107 astring1 = UnicodeToAsciiString((LPWSTR)lpApplicationName);
2108 if(lpCommandLine)
2109 astring2 = UnicodeToAsciiString(lpCommandLine);
2110 if(lpCurrentDirectory)
2111 astring3 = UnicodeToAsciiString((LPWSTR)lpCurrentDirectory);
2112 rc = CreateProcessA(astring1, astring2, lpProcessAttributes, lpThreadAttributes,
2113 bInheritHandles, dwCreationFlags, lpEnvironment,
2114 astring3, (LPSTARTUPINFOA)lpStartupInfo,
2115 lpProcessInfo);
2116 if(astring3) FreeAsciiString(astring3);
2117 if(astring2) FreeAsciiString(astring2);
2118 if(astring1) FreeAsciiString(astring1);
2119 return(rc);
2120}
2121//******************************************************************************
2122//******************************************************************************
2123HINSTANCE WIN32API WinExec(LPCSTR lpCmdLine, UINT nCmdShow)
2124{
2125 STARTUPINFOA startinfo = {0};
2126 PROCESS_INFORMATION procinfo;
2127 DWORD rc;
2128 HINSTANCE hInstance;
2129
2130 dprintf(("KERNEL32: WinExec %s\n", lpCmdLine));
2131 startinfo.dwFlags = nCmdShow;
2132 if(CreateProcessA(NULL, (LPSTR)lpCmdLine, NULL, NULL, FALSE, 0, NULL, NULL,
2133 &startinfo, &procinfo) == FALSE)
2134 {
2135 hInstance = (HINSTANCE)GetLastError();
2136 if(hInstance >= 32) {
2137 hInstance = 11;
2138 }
2139 dprintf(("KERNEL32: WinExec failed with rc %d", hInstance));
2140 return hInstance;
2141 }
2142 //block until the launched app waits for input (or a timeout of 15 seconds)
2143 //TODO: Shouldn't call Open32, but the api in user32..
2144 if(fVersionWarp3) {
2145 Sleep(1000); //WaitForInputIdle not available in Warp 3
2146 }
2147 else {
2148 dprintf(("Calling WaitForInputIdle %x %d", procinfo.hProcess, 15000));
2149 rc = WaitForInputIdle(procinfo.hProcess, 15000);
2150#ifdef DEBUG
2151 if(rc != 0) {
2152 dprintf(("WinExec: WaitForInputIdle %x returned %x", procinfo.hProcess, rc));
2153 }
2154 else dprintf(("WinExec: WaitForInputIdle successfull"));
2155#endif
2156 }
2157 CloseHandle(procinfo.hThread);
2158 CloseHandle(procinfo.hProcess);
2159 return 33;
2160}
2161//******************************************************************************
2162//DWORD idAttach; /* thread to attach */
2163//DWORD idAttachTo; /* thread to attach to */
2164//BOOL fAttach; /* attach or detach */
2165//******************************************************************************
2166BOOL WIN32API AttachThreadInput(DWORD idAttach, DWORD idAttachTo, BOOL fAttach)
2167{
2168 dprintf(("USER32: AttachThreadInput, not implemented\n"));
2169 return(TRUE);
2170}
2171//******************************************************************************
2172//******************************************************************************
2173DWORD WIN32API WaitForInputIdle(HANDLE hProcess, DWORD dwTimeOut)
2174{
2175 dprintf(("USER32: WaitForInputIdle %x %d\n", hProcess, dwTimeOut));
2176
2177 if(fVersionWarp3) {
2178 Sleep(1000);
2179 return 0;
2180 }
2181 else return O32_WaitForInputIdle(hProcess, dwTimeOut);
2182}
2183/**********************************************************************
2184 * LoadModule (KERNEL32.499)
2185 *
2186 * Wine: 20000909
2187 *
2188 * Copyright 1995 Alexandre Julliard
2189 */
2190HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock )
2191{
2192 LOADPARAMS *params = (LOADPARAMS *)paramBlock;
2193 PROCESS_INFORMATION info;
2194 STARTUPINFOA startup;
2195 HINSTANCE hInstance;
2196 LPSTR cmdline, p;
2197 char filename[MAX_PATH];
2198 BYTE len;
2199
2200 dprintf(("LoadModule %s %x", name, paramBlock));
2201
2202 if (!name) return ERROR_FILE_NOT_FOUND;
2203
2204 if (!SearchPathA( NULL, name, ".exe", sizeof(filename), filename, NULL ) &&
2205 !SearchPathA( NULL, name, NULL, sizeof(filename), filename, NULL ))
2206 return GetLastError();
2207
2208 len = (BYTE)params->lpCmdLine[0];
2209 if (!(cmdline = (LPSTR)HeapAlloc( GetProcessHeap(), 0, strlen(filename) + len + 2 )))
2210 return ERROR_NOT_ENOUGH_MEMORY;
2211
2212 strcpy( cmdline, filename );
2213 p = cmdline + strlen(cmdline);
2214 *p++ = ' ';
2215 memcpy( p, params->lpCmdLine + 1, len );
2216 p[len] = 0;
2217
2218 memset( &startup, 0, sizeof(startup) );
2219 startup.cb = sizeof(startup);
2220 if (params->lpCmdShow)
2221 {
2222 startup.dwFlags = STARTF_USESHOWWINDOW;
2223 startup.wShowWindow = params->lpCmdShow[1];
2224 }
2225
2226 if (CreateProcessA( filename, cmdline, NULL, NULL, FALSE, 0,
2227 params->lpEnvAddress, NULL, &startup, &info ))
2228 {
2229 /* Give 15 seconds to the app to come up */
2230 if ( WaitForInputIdle ( info.hProcess, 15000 ) == 0xFFFFFFFF )
2231 dprintf(("ERROR: WaitForInputIdle failed: Error %ld\n", GetLastError() ));
2232 hInstance = 33;
2233 /* Close off the handles */
2234 CloseHandle( info.hThread );
2235 CloseHandle( info.hProcess );
2236 }
2237 else if ((hInstance = GetLastError()) >= 32)
2238 {
2239 dprintf(("ERROR: Strange error set by CreateProcess: %d\n", hInstance ));
2240 hInstance = 11;
2241 }
2242
2243 HeapFree( GetProcessHeap(), 0, cmdline );
2244 return hInstance;
2245}
2246//******************************************************************************
2247//******************************************************************************
2248FARPROC WIN32API GetProcAddress(HMODULE hModule, LPCSTR lpszProc)
2249{
2250 Win32ImageBase *winmod;
2251 FARPROC proc;
2252 ULONG ulAPIOrdinal;
2253
2254 if(hModule == 0 || hModule == -1 || (WinExe && hModule == WinExe->getInstanceHandle())) {
2255 winmod = WinExe;
2256 }
2257 else winmod = (Win32ImageBase *)Win32DllBase::findModule((HINSTANCE)hModule);
2258
2259 if(winmod) {
2260 ulAPIOrdinal = (ULONG)lpszProc;
2261 if (ulAPIOrdinal <= 0x0000FFFF) {
2262 proc = (FARPROC)winmod->getApi((int)ulAPIOrdinal);
2263 }
2264 else proc = (FARPROC)winmod->getApi((char *)lpszProc);
2265 if(proc == 0) {
2266#ifdef DEBUG
2267 if(ulAPIOrdinal <= 0x0000FFFF) {
2268 dprintf(("GetProcAddress %x %x not found!", hModule, ulAPIOrdinal));
2269 }
2270 else dprintf(("GetProcAddress %x %s not found!", hModule, lpszProc));
2271#endif
2272 SetLastError(ERROR_PROC_NOT_FOUND);
2273 }
2274 if(HIWORD(lpszProc))
2275 dprintf(("KERNEL32: GetProcAddress %s from %X returned %X\n", lpszProc, hModule, proc));
2276 else dprintf(("KERNEL32: GetProcAddress %x from %X returned %X\n", lpszProc, hModule, proc));
2277
2278 SetLastError(ERROR_SUCCESS);
2279 return proc;
2280 }
2281 proc = (FARPROC)OSLibDosGetProcAddress(hModule, lpszProc);
2282 if(HIWORD(lpszProc))
2283 dprintf(("KERNEL32: GetProcAddress %s from %X returned %X\n", lpszProc, hModule, proc));
2284 else dprintf(("KERNEL32: GetProcAddress %x from %X returned %X\n", lpszProc, hModule, proc));
2285 SetLastError(ERROR_SUCCESS);
2286 return(proc);
2287}
2288//******************************************************************************
2289// ODIN_SetProcAddress: Override a dll export
2290//
2291// Parameters:
2292// HMODULE hModule Module handle
2293// LPCSTR lpszProc Export name or ordinal
2294// FARPROC pfnNewProc New export function address
2295//
2296// Returns: Success -> old address of export
2297// Failure -> -1
2298//
2299//******************************************************************************
2300FARPROC WIN32API ODIN_SetProcAddress(HMODULE hModule, LPCSTR lpszProc,
2301 FARPROC pfnNewProc)
2302{
2303 Win32ImageBase *winmod;
2304 FARPROC proc;
2305 ULONG ulAPIOrdinal;
2306
2307 if(hModule == 0 || hModule == -1 || (WinExe && hModule == WinExe->getInstanceHandle())) {
2308 winmod = WinExe;
2309 }
2310 else winmod = (Win32ImageBase *)Win32DllBase::findModule((HINSTANCE)hModule);
2311
2312 if(winmod) {
2313 ulAPIOrdinal = (ULONG)lpszProc;
2314 if (ulAPIOrdinal <= 0x0000FFFF) {
2315 proc = (FARPROC)winmod->setApi((int)ulAPIOrdinal, (ULONG)pfnNewProc);
2316 }
2317 else proc = (FARPROC)winmod->setApi((char *)lpszProc, (ULONG)pfnNewProc);
2318 if(proc == 0) {
2319#ifdef DEBUG
2320 if(ulAPIOrdinal <= 0x0000FFFF) {
2321 dprintf(("ODIN_SetProcAddress %x %x not found!", hModule, ulAPIOrdinal));
2322 }
2323 else dprintf(("ODIN_SetProcAddress %x %s not found!", hModule, lpszProc));
2324#endif
2325 SetLastError(ERROR_PROC_NOT_FOUND);
2326 }
2327 if(HIWORD(lpszProc))
2328 dprintf(("KERNEL32: ODIN_SetProcAddress %s from %X returned %X\n", lpszProc, hModule, proc));
2329 else dprintf(("KERNEL32: ODIN_SetProcAddress %x from %X returned %X\n", lpszProc, hModule, proc));
2330
2331 SetLastError(ERROR_SUCCESS);
2332 return proc;
2333 }
2334 SetLastError(ERROR_INVALID_HANDLE);
2335 return (FARPROC)-1;
2336}
2337//******************************************************************************
2338//Retrieve the version
2339//******************************************************************************
2340BOOL SYSTEM GetVersionStruct(char *lpszModName, char *verstruct, ULONG bufLength)
2341{
2342 Win32ImageBase *winimage;
2343 HINSTANCE hDll;
2344 BOOL rc = FALSE;
2345
2346 dprintf(("GetVersionStruct of module %s %x %d", lpszModName, verstruct, bufLength));
2347 if(verstruct == NULL) {
2348 SetLastError(ERROR_INVALID_PARAMETER);
2349 return FALSE;
2350 }
2351 if (WinExe != NULL && WinExe->matchModName(lpszModName)) {
2352 return WinExe->getVersionStruct(verstruct, bufLength);
2353 }
2354 hDll = LoadLibraryExA(lpszModName, 0, LOAD_LIBRARY_AS_DATAFILE);
2355 if(hDll == 0) {
2356 dprintf(("ERROR: GetVersionStruct: Unable to load module!!"));
2357 return 0;
2358 }
2359 winimage = (Win32ImageBase *)Win32DllBase::findModule(hDll);
2360 if(winimage != NULL) {
2361 rc = winimage->getVersionStruct(verstruct, bufLength);
2362 }
2363 else {
2364 dprintf(("GetVersionStruct; just loaded dll %s, but can't find it now!", lpszModName));
2365//// DebugInt3();
2366 }
2367 FreeLibrary(hDll);
2368 return rc;
2369}
2370//******************************************************************************
2371//******************************************************************************
2372ULONG SYSTEM GetVersionSize(char *lpszModName)
2373{
2374 Win32ImageBase *winimage;
2375 HINSTANCE hDll;
2376 ULONG size = 0;
2377
2378 dprintf(("GetVersionSize of %s", lpszModName));
2379 if (WinExe != NULL && WinExe->matchModName(lpszModName)) {
2380 return WinExe->getVersionSize();
2381 }
2382
2383 hDll = LoadLibraryExA(lpszModName, 0, LOAD_LIBRARY_AS_DATAFILE);
2384 if(hDll == 0) {
2385 dprintf(("ERROR: GetVersionStruct: Unable to load module!!"));
2386 return 0;
2387 }
2388 winimage = (Win32ImageBase *)Win32DllBase::findModule(hDll);
2389 if(winimage != NULL) {
2390 size = winimage->getVersionSize();
2391 }
2392 else {
2393 dprintf(("GetVersionSize; just loaded dll %s, but can't find it now!", lpszModName));
2394//// DebugInt3();
2395 }
2396 FreeLibrary(hDll);
2397 return size;
2398}
2399//******************************************************************************
2400//******************************************************************************
2401BOOL WIN32API DisableThreadLibraryCalls(HMODULE hModule)
2402{
2403 Win32DllBase *winmod;
2404 FARPROC proc;
2405 ULONG ulAPIOrdinal;
2406
2407 winmod = Win32DllBase::findModule((HINSTANCE)hModule);
2408 if(winmod)
2409 {
2410 // don't call ATTACH/DETACH thread functions in DLL
2411 winmod->disableThreadLibraryCalls();
2412 return TRUE;
2413 }
2414 else
2415 {
2416 // raise error condition
2417 SetLastError(ERROR_INVALID_HANDLE);
2418 return FALSE;
2419 }
2420}
2421//******************************************************************************
2422//******************************************************************************
Note: See TracBrowser for help on using the repository browser.