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

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

kernel32: Add support for custom PE/PEC/W16ODIN paths to ODIN.INI.

This is needed since the RPM package of Odin installs these tools to a
directory which is not the same as the one where kernel32.dll is located.
Together with the fix of the RPM spec (coming later) this fixes the broken
PE and PEC functionality when Odin is installed from RPM.

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