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

Last change on this file since 21463 was 21463, checked in by dmik, 15 years ago

Undo interpreting strings as ANSI for certain OSLib APIs modified in the previous commits as it breaks the common logic where many other OSLib calls (e.g. all dealig with file names) seem to expect the OEM (OS/2) encoding.

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