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

Last change on this file since 9262 was 9262, checked in by sandervl, 23 years ago

Added code to print leaked heap memory

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