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

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

PF: renamed RtlAllocateAndInitializeSid

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