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

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

kernel32: Cut out hidden kLIBC arguments added by spawn().

These arguments are not intended to be seen by the application and
should not appear in GetCommandLine().

This is a temporary solution (see svn.netlabs.org/libc/ticket/260 for details).

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 = TRUE; // 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.