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

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