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

Last change on this file since 21619 was 21619, checked in by dmik, 14 years ago

kernel32: Removed the dirty hack that would reset the exception handler chain before calling DosExit(). This prevented exception handlers in the chain from being called at thread termination and performing the necessary cleanup which is sometimes vital (like releasing locked resources etc).

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