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

Last change on this file since 22010 was 22010, checked in by dmik, 13 years ago

kernel32: Disable Win32 TIB switch completely by default.

Previously, It was ON until the EXE type had been identified (e.g. when
loading KERNEL32.DLL and the DLLs it drags in). This could make
some apps spin in an exception handler loop (like OpenOffice
trying to load JVM.DLL).

This closes #83.

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