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

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

minor log change

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