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

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

Added function to override loader names (pe/pec/w16odin)

File size: 87.7 KB
Line 
1/* $Id: wprocess.cpp,v 1.161 2002-12-03 11:39:40 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 cch = strlen(pszCmdLineA) + 1;
1404
1405 pszCmdLineW = (WCHAR*)malloc(cch * 2);
1406 if (pszCmdLineW != NULL) {
1407 //Translate from OS/2 to Windows codepage & ascii to unicode
1408 MultiByteToWideChar(CP_OEMCP, 0, pszCmdLineA, -1, (LPWSTR)pszCmdLineW, cch-1);
1409 ((LPWSTR)pszCmdLineW)[cch-1] = 0;
1410
1411 //ascii command line is still in OS/2 codepage, so convert it
1412 WideCharToMultiByte(CP_ACP, 0, pszCmdLineW, -1, (LPSTR)pszCmdLineA, cch-1, 0, NULL);
1413 ((LPSTR)pszCmdLineA)[cch-1] = 0;
1414 }
1415 else
1416 {
1417 DebugInt3();
1418 dprintf(("KERNEL32: InitCommandLine(%p): malloc(%d) failed (2)\n", pszPeExe, cch));
1419 rc = ERROR_NOT_ENOUGH_MEMORY;
1420 }
1421 }
1422
1423 return rc;
1424}
1425
1426/**
1427 * Gets the command line of the current process.
1428 * @returns On success:
1429 * Command line of the current process. One single string.
1430 * The first part of the command line string is the executable filename
1431 * of the current process. It might be in quotes if it contains spaces.
1432 * The rest of the string is arguments.
1433 *
1434 * On error:
1435 * NULL. Last error set. (does Win32 set last error this?)
1436 * @sketch IF not inited THEN
1437 * Init commandline assuming !PE.EXE
1438 * IF init failes THEN set last error.
1439 * ENDIF
1440 * return ASCII/ANSI commandline.
1441 * @status Completely implemented and tested.
1442 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1443 * @remark The Ring-3 PeLdr is resposible for calling InitCommandLine before anyone
1444 * is able to call this function.
1445 */
1446LPCSTR WIN32API GetCommandLineA(VOID)
1447{
1448 /*
1449 * Check if the commandline is initiated.
1450 * If not we'll have to do it.
1451 * ASSUMES that if not inited this isn't a PE.EXE lauched process.
1452 */
1453 if (pszCmdLineA == NULL)
1454 {
1455 APIRET rc;
1456 rc = InitCommandLine(NULL);
1457 if (rc != NULL)
1458 SetLastError(rc);
1459 }
1460
1461 dprintf(("KERNEL32: GetCommandLineA: %s\n", pszCmdLineA));
1462 return pszCmdLineA;
1463}
1464
1465
1466/**
1467 * Gets the command line of the current process.
1468 * @returns On success:
1469 * Command line of the current process. One single string.
1470 * The first part of the command line string is the executable filename
1471 * of the current process. It might be in quotes if it contains spaces.
1472 * The rest of the string is arguments.
1473 *
1474 * On error:
1475 * NULL. Last error set. (does Win32 set last error this?)
1476 * @sketch IF not inited THEN
1477 * Init commandline assuming !PE.EXE
1478 * IF init failes THEN set last error.
1479 * ENDIF
1480 * return Unicode commandline.
1481 * @status Completely implemented and tested.
1482 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1483 * @remark The Ring-3 PeLdr is resposible for calling InitCommandLine before anyone
1484 * is able to call this function.
1485 */
1486LPCWSTR WIN32API GetCommandLineW(void)
1487{
1488 /*
1489 * Check if the commandline is initiated.
1490 * If not we'll have to do it.
1491 * ASSUMES that if not inited this isn't a PE.EXE lauched process.
1492 */
1493 if (pszCmdLineW == NULL)
1494 {
1495 APIRET rc;
1496 rc = InitCommandLine(NULL);
1497 if (rc != NULL)
1498 SetLastError(rc);
1499 }
1500
1501 dprintf(("KERNEL32: GetCommandLineW: %s\n", pszCmdLineA));
1502 return pszCmdLineW;
1503}
1504
1505
1506/**
1507 * GetModuleFileName gets the full path and file name for the specified module.
1508 * @returns Bytes written to the buffer (lpszPath). This count includes the
1509 * terminating '\0'.
1510 * On error 0 is returned. Last error is set.
1511 *
1512 * 2002-04-25 PH
1513 * Q - Do we set ERROR_BUFFER_OVERFLOW when cch > cchPath?
1514 * Q - Does NT really set the last error?
1515 * A > Win2k does not set LastError here, remains OK
1516 *
1517 * While GetModuleFileName does add a trailing termination zero
1518 * if there is enough room, the returned number of characters
1519 * *MUST NOT* include the zero character!
1520 * (Notes R6 Installer on Win2kSP6, verified Testcase)
1521 *
1522 * @param hModule Handle to the module you like to get the file name to.
1523 * @param lpszPath Output buffer for full path and file name.
1524 * @param cchPath Size of the lpszPath buffer.
1525 * @sketch Validate lpszPath.
1526 * Find the module object using handle.
1527 * If found Then
1528 * Get full path from module object.
1529 * If found path Then
1530 * Copy path to buffer and set the number of bytes written.
1531 * Else
1532 * IPE!
1533 * Else
1534 * Call Open32 GetModuleFileName. (kernel32 initterm needs/needed this)
1535 * Log result.
1536 * Return number of bytes written to the buffer.
1537 *
1538 * @status Completely implemented, Open32.
1539 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1540 * Sander van Leeuwen (sandervl@xs4all.nl)
1541 * Patrick Haller (patrick.haller@innotek.de)
1542 * @remark - Do we still have to call Open32?
1543 */
1544DWORD WIN32API GetModuleFileNameA(HMODULE hModule, LPTSTR lpszPath, DWORD cchPath)
1545{
1546 Win32ImageBase * pMod; /* Pointer to the module object. */
1547 DWORD cch = 0; /* Length of the */
1548
1549 // PH 2002-04-24 Note:
1550 // WIN2k just crashes in NTDLL if lpszPath is invalid!
1551 if (!VALID_PSZ(lpszPath))
1552 {
1553 dprintf(("KERNEL32: GetModuleFileNameA(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
1554 hModule, lpszPath, cchPath, lpszPath));
1555 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
1556 return 0;
1557 }
1558
1559 pMod = Win32ImageBase::findModule(hModule);
1560 if (pMod != NULL)
1561 {
1562 const char *pszFn = pMod->getFullPath();
1563 if (pszFn)
1564 {
1565 cch = strlen(pszFn);
1566 if (cch >= cchPath)
1567 cch = cchPath;
1568 else
1569 // if there is sufficient room for the zero termination,
1570 // write it additionally, uncounted
1571 lpszPath[cch] = '\0';
1572
1573 memcpy(lpszPath, pszFn, cch);
1574 }
1575 else
1576 {
1577 dprintf(("KERNEL32: GetModuleFileNameA(%x,...): IPE - getFullPath returned NULL or empty string\n"));
1578 DebugInt3();
1579 SetLastError(ERROR_INVALID_HANDLE);
1580 }
1581 }
1582 else
1583 {
1584 SetLastError(ERROR_INVALID_HANDLE);
1585 //only needed for call inside kernel32's initterm (profile init)
1586 //(console init only it seems...)
1587 cch = OSLibDosGetModuleFileName(hModule, lpszPath, cchPath);
1588 }
1589
1590 if (cch > 0)
1591 dprintf(("KERNEL32: GetModuleFileNameA(%x %x): %s %d\n", hModule, lpszPath, lpszPath, cch));
1592 else
1593 dprintf(("KERNEL32: WARNING: GetModuleFileNameA(%x,...) - not found!", hModule));
1594
1595 return cch;
1596}
1597
1598
1599/**
1600 * GetModuleFileName gets the full path and file name for the specified module.
1601 * @returns Bytes written to the buffer (lpszPath). This count includes the
1602 * terminating '\0'.
1603 * On error 0 is returned. Last error is set.
1604 * @param hModule Handle to the module you like to get the file name to.
1605 * @param lpszPath Output buffer for full path and file name.
1606 * @param cchPath Size of the lpszPath buffer.
1607 * @sketch Find the module object using handle.
1608 * If found Then
1609 * get full path from module object.
1610 * If found path Then
1611 * Determin path length.
1612 * Translate the path to into the buffer.
1613 * Else
1614 * IPE.
1615 * else
1616 * SetLastError to invalid handle.
1617 * Log result.
1618 * return number of bytes written to the buffer.
1619 *
1620 * @status Completely implemented.
1621 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
1622 * @remark - We do _NOT_ call Open32.
1623 * - Do we set ERROR_BUFFER_OVERFLOW when cch > cchPath?
1624 * - Does NT really set the last error?
1625 */
1626DWORD WIN32API GetModuleFileNameW(HMODULE hModule, LPWSTR lpszPath, DWORD cchPath)
1627{
1628 Win32ImageBase * pMod;
1629 DWORD cch = 0;
1630
1631 if (!VALID_PSZ(lpszPath))
1632 {
1633 dprintf(("KERNEL32: GetModuleFileNameW(0x%x, 0x%x, 0x%x): invalid pointer lpszLibFile = 0x%x\n",
1634 hModule, lpszPath, cchPath, lpszPath));
1635 SetLastError(ERROR_INVALID_PARAMETER); //or maybe ERROR_ACCESS_DENIED is more appropriate?
1636 return 0;
1637 }
1638
1639 pMod = Win32ImageBase::findModule(hModule);
1640 if (pMod != NULL)
1641 {
1642 const char *pszFn = pMod->getFullPath();
1643 if (pszFn || *pszFn != '\0')
1644 {
1645 cch = strlen(pszFn) + 1;
1646 if (cch > cchPath)
1647 cch = cchPath;
1648 AsciiToUnicodeN(pszFn, lpszPath, cch);
1649 }
1650 else
1651 {
1652 dprintf(("KERNEL32: GetModuleFileNameW(%x,...): IPE - getFullPath returned NULL or empty string\n"));
1653 DebugInt3();
1654 SetLastError(ERROR_INVALID_HANDLE);
1655 }
1656 }
1657 else
1658 SetLastError(ERROR_INVALID_HANDLE);
1659
1660 if (cch > 0)
1661 dprintf(("KERNEL32: GetModuleFileNameW(%x,...): %s %d\n", hModule, lpszPath, cch));
1662 else
1663 dprintf(("KERNEL32: WARNING: GetModuleFileNameW(%x,...) - not found!", hModule));
1664
1665 return cch;
1666}
1667
1668
1669//******************************************************************************
1670//NOTE: GetModuleHandleA does NOT support files with multiple dots (i.e.
1671// very.weird.exe)
1672//
1673// hinst = LoadLibrary("WINSPOOL.DRV"); -> succeeds
1674// hinst2 = GetModuleHandle("WINSPOOL.DRV"); -> succeeds
1675// hinst3 = GetModuleHandle("WINSPOOL."); -> fails
1676// hinst4 = GetModuleHandle("WINSPOOL"); -> fails
1677// hinst = LoadLibrary("KERNEL32.DLL"); -> succeeds
1678// hinst2 = GetModuleHandle("KERNEL32.DLL"); -> succeeds
1679// hinst3 = GetModuleHandle("KERNEL32."); -> fails
1680// hinst4 = GetModuleHandle("KERNEL32"); -> succeeds
1681// Same behaviour as observed in NT4, SP6
1682//******************************************************************************
1683HANDLE WIN32API GetModuleHandleA(LPCTSTR lpszModule)
1684{
1685 HANDLE hMod = 0;
1686 Win32DllBase *windll;
1687 char szModule[CCHMAXPATH];
1688 char *dot;
1689
1690 if(lpszModule == NULL)
1691 {
1692 if(WinExe)
1693 hMod = WinExe->getInstanceHandle();
1694 else
1695 {
1696 // // Just fail this API
1697 // hMod = 0;
1698 // SetLastError(ERROR_INVALID_HANDLE);
1699 // Wrong: in an ODIN32-LX environment, just
1700 // assume a fake handle
1701 hMod = -1;
1702 }
1703 }
1704 else
1705 {
1706 strcpy(szModule, OSLibStripPath((char *)lpszModule));
1707 strupr(szModule);
1708 dot = strchr(szModule, '.');
1709 if(dot == NULL) {
1710 //if no extension -> add .DLL (see SDK docs)
1711 strcat(szModule, DLL_EXTENSION);
1712 }
1713 else {
1714 if(dot[1] == 0) {
1715 //a trailing dot means the module has no extension (SDK docs)
1716 *dot = 0;
1717 }
1718 }
1719 if(WinExe && WinExe->matchModName(szModule)) {
1720 hMod = WinExe->getInstanceHandle();
1721 }
1722 else {
1723 windll = Win32DllBase::findModule(szModule);
1724 if(windll) {
1725 hMod = windll->getInstanceHandle();
1726 }
1727 }
1728 }
1729 dprintf(("KERNEL32: GetModuleHandle %s returned %X\n", lpszModule, hMod));
1730 return(hMod);
1731}
1732//******************************************************************************
1733//******************************************************************************
1734HMODULE WIN32API GetModuleHandleW(LPCWSTR lpwszModuleName)
1735{
1736 HMODULE rc;
1737 char *astring = NULL;
1738
1739 if (NULL != lpwszModuleName)
1740 astring = UnicodeToAsciiString((LPWSTR)lpwszModuleName);
1741
1742 rc = GetModuleHandleA(astring);
1743 dprintf(("KERNEL32: OS2GetModuleHandleW %s returned %X\n", astring, rc));
1744
1745 if (NULL != astring)
1746 FreeAsciiString(astring);
1747
1748 return(rc);
1749}
1750//******************************************************************************
1751//******************************************************************************
1752const char *szPECmdLoader = "PEC.EXE";
1753const char *szPEGUILoader = "PE.EXE";
1754const char *szNELoader = "w16odin.exe";
1755//******************************************************************************
1756//Override loader names (PEC, PE, W16ODIN)
1757//NOTE: String must be resident
1758//******************************************************************************
1759BOOL WIN32API ODIN_SetLoaders(LPCSTR pszPECmdLoader, LPCSTR pszPEGUILoader,
1760 LPCSTR pszNELoader)
1761{
1762 if(pszPECmdLoader) szPECmdLoader = pszPECmdLoader;
1763 if(pszPEGUILoader) szPEGUILoader = pszPEGUILoader;
1764 if(pszNELoader) szNELoader = pszNELoader;
1765
1766 return TRUE;
1767}
1768//******************************************************************************
1769//******************************************************************************
1770BOOL WINAPI CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine,
1771 LPSECURITY_ATTRIBUTES lpProcessAttributes,
1772 LPSECURITY_ATTRIBUTES lpThreadAttributes,
1773 BOOL bInheritHandles, DWORD dwCreationFlags,
1774 LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
1775 LPSTARTUPINFOA lpStartupInfo,
1776 LPPROCESS_INFORMATION lpProcessInfo )
1777{
1778 TEB *pThreadDB = (TEB*)GetThreadTEB();
1779 char *cmdline = NULL;
1780 BOOL rc;
1781
1782 dprintf(("KERNEL32: CreateProcessA %s cline:%s inherit:%d cFlags:%x Env:%x CurDir:%s StartupFlags:%x\n",
1783 lpApplicationName, lpCommandLine, bInheritHandles, dwCreationFlags,
1784 lpEnvironment, lpCurrentDirectory, lpStartupInfo));
1785
1786#ifdef DEBUG
1787 if(lpStartupInfo) {
1788 dprintf(("lpStartupInfo->lpReserved %x", lpStartupInfo->lpReserved));
1789 dprintf(("lpStartupInfo->lpDesktop %x", lpStartupInfo->lpDesktop));
1790 dprintf(("lpStartupInfo->lpTitle %s", lpStartupInfo->lpTitle));
1791 dprintf(("lpStartupInfo->dwX %x", lpStartupInfo->dwX));
1792 dprintf(("lpStartupInfo->dwY %x", lpStartupInfo->dwY));
1793 dprintf(("lpStartupInfo->dwXSize %x", lpStartupInfo->dwXSize));
1794 dprintf(("lpStartupInfo->dwYSize %x", lpStartupInfo->dwYSize));
1795 dprintf(("lpStartupInfo->dwXCountChars %x", lpStartupInfo->dwXCountChars));
1796 dprintf(("lpStartupInfo->dwYCountChars %x", lpStartupInfo->dwYCountChars));
1797 dprintf(("lpStartupInfo->dwFillAttribute %x", lpStartupInfo->dwFillAttribute));
1798 dprintf(("lpStartupInfo->dwFlags %x", lpStartupInfo->dwFlags));
1799 dprintf(("lpStartupInfo->wShowWindow %x", lpStartupInfo->wShowWindow));
1800 dprintf(("lpStartupInfo->hStdInput %x", lpStartupInfo->hStdInput));
1801 dprintf(("lpStartupInfo->hStdOutput %x", lpStartupInfo->hStdOutput));
1802 dprintf(("lpStartupInfo->hStdError %x", lpStartupInfo->hStdError));
1803 }
1804#endif
1805
1806 // open32 does not support DEBUG_ONLY_THIS_PROCESS
1807 if(dwCreationFlags & DEBUG_ONLY_THIS_PROCESS)
1808 dwCreationFlags |= DEBUG_PROCESS;
1809
1810 if(O32_CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes,
1811 lpThreadAttributes, bInheritHandles, dwCreationFlags,
1812 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
1813 lpProcessInfo) == TRUE)
1814 {
1815 if (dwCreationFlags & DEBUG_PROCESS && pThreadDB != NULL)
1816 {
1817 if(pThreadDB->o.odin.pidDebuggee != 0)
1818 {
1819 // TODO: handle this
1820 dprintf(("KERNEL32: CreateProcess ERROR: This thread is already a debugger\n"));
1821 }
1822 else
1823 {
1824 pThreadDB->o.odin.pidDebuggee = lpProcessInfo->dwProcessId;
1825 OSLibStartDebugger((ULONG*)&pThreadDB->o.odin.pidDebuggee);
1826 }
1827 }
1828 else pThreadDB->o.odin.pidDebuggee = 0;
1829
1830 return(TRUE);
1831 }
1832
1833 // PH 2001-05-07
1834 // verify why O32_CreateProcess actually failed.
1835 // If GetLastError() == 191 (ERROR_INVALID_EXE_SIGNATURE)
1836 // we can continue to call "PE.EXE".
1837 // Note: Open32 does not translate ERROR_INVALID_EXE_SIGNATURE,
1838 // it is also valid in Win32.
1839 DWORD dwError = GetLastError();
1840 if (ERROR_INVALID_EXE_SIGNATURE != dwError && ERROR_FILE_NOT_FOUND != dwError && ERROR_ACCESS_DENIED != dwError)
1841 {
1842 dprintf(("CreateProcess: O32_CreateProcess failed with rc=%d, not PE-executable !",
1843 dwError));
1844
1845 // the current value of GetLastError() is still valid.
1846
1847 return FALSE;
1848 }
1849
1850 // else ...
1851
1852 //probably a win32 exe, so run it in the pe loader
1853 if(lpApplicationName) {
1854 if(lpCommandLine) {
1855 //skip exe name in lpCommandLine
1856 //TODO: doesn't work for directories with spaces!
1857 while(*lpCommandLine != 0 && *lpCommandLine != ' ')
1858 lpCommandLine++;
1859
1860 if(*lpCommandLine != 0) {
1861 lpCommandLine++;
1862 }
1863 cmdline = (char *)malloc(strlen(lpApplicationName)+strlen(lpCommandLine) + 16);
1864 sprintf(cmdline, "%s %s", lpApplicationName, lpCommandLine);
1865 }
1866 else {
1867 cmdline = (char *)malloc(strlen(lpApplicationName) + 16);
1868 sprintf(cmdline, "%s", lpApplicationName);
1869 }
1870 }
1871 else {
1872 cmdline = (char *)malloc(strlen(lpCommandLine) + 16);
1873 sprintf(cmdline, "%s", lpCommandLine);
1874 }
1875
1876 char szAppName[MAX_PATH];
1877 char buffer[MAX_PATH];
1878 DWORD fileAttr;
1879 char *exename = buffer;
1880 strncpy(buffer, cmdline, sizeof(szAppName));
1881 buffer[MAX_PATH-1] = 0;
1882 if(*exename == '"') {
1883 exename++;
1884 while(*exename != 0 && *exename != '"')
1885 exename++;
1886
1887 if(*exename != 0) {
1888 *exename = 0;
1889 }
1890 exename++;
1891 if (SearchPathA( NULL, &buffer[1], ".exe", sizeof(szAppName), szAppName, NULL ) ||
1892 SearchPathA( NULL, &buffer[1], NULL, sizeof(szAppName), szAppName, NULL ))
1893 {
1894 //
1895 }
1896 }
1897 else {
1898 BOOL fTerminate = FALSE;
1899 DWORD fileAttr;
1900
1901 while(*exename != 0) {
1902 while(*exename != 0 && *exename != ' ')
1903 exename++;
1904
1905 if(*exename != 0) {
1906 *exename = 0;
1907 fTerminate = TRUE;
1908 }
1909 dprintf(("Trying '%s'", buffer ));
1910 if (SearchPathA( NULL, buffer, ".exe", sizeof(szAppName), szAppName, NULL ) ||
1911 SearchPathA( NULL, buffer, NULL, sizeof(szAppName), szAppName, NULL ))
1912 {
1913 if(fTerminate) exename++;
1914 break;
1915 }
1916
1917 if(fTerminate) {
1918 *exename = ' ';
1919 exename++;
1920 fTerminate = FALSE;
1921 }
1922 }
1923 }
1924 lpCommandLine = exename; //start of command line parameters
1925
1926 fileAttr = GetFileAttributesA(szAppName);
1927 if(fileAttr == -1 || (fileAttr & FILE_ATTRIBUTE_DIRECTORY)) {
1928 dprintf(("CreateProcess: can't find executable!"));
1929 SetLastError(ERROR_FILE_NOT_FOUND);
1930 return FALSE;
1931 }
1932
1933 dprintf(("KERNEL32: CreateProcess %s %s", szAppName, lpCommandLine));
1934
1935 DWORD Characteristics, SubSystem, fNEExe;
1936 if(Win32ImageBase::isPEImage(szAppName, &Characteristics, &SubSystem, &fNEExe) == 0)
1937 {
1938 char *lpszPE;
1939 char *lpszExecutable;
1940 int iNewCommandLineLength;
1941
1942 // calculate base length for the new command line
1943 iNewCommandLineLength = strlen(szAppName) + strlen(lpCommandLine);
1944
1945 if(SubSystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
1946 lpszExecutable = (LPSTR)szPECmdLoader;
1947 else
1948 lpszExecutable = (LPSTR)szPEGUILoader;
1949
1950 lpszPE = lpszExecutable;
1951
1952 // 2002-04-24 PH
1953 // set the ODIN32.DEBUG_CHILD environment variable to start new PE processes
1954 // under a new instance of the (IPMD) debugger.
1955#ifdef DEBUG
1956 CHAR debug_szPE[ 512 ];
1957 PSZ debug_pszOS2Debugger = getenv("ODIN32.DEBUG_CHILD");
1958 if (NULL != debug_pszOS2Debugger)
1959 {
1960 // build new start command
1961 strcpy(debug_szPE, debug_pszOS2Debugger);
1962 strcat(debug_szPE, " ");
1963 strcat(debug_szPE, lpszExecutable);
1964
1965 // we require more space in the new command line
1966 iNewCommandLineLength += strlen( debug_szPE );
1967
1968 // only launch the specified executable (ICSDEBUG.EXE)
1969 lpszPE = debug_szPE;
1970 lpszExecutable = debug_pszOS2Debugger;
1971 }
1972#endif
1973
1974 //SvL: Allright. Before we call O32_CreateProcess, we must take care of
1975 // lpCurrentDirectory ourselves. (Open32 ignores it!)
1976 if(lpCurrentDirectory) {
1977 char *newcmdline;
1978
1979 newcmdline = (char *)malloc(strlen(lpCurrentDirectory) + iNewCommandLineLength + 32);
1980 sprintf(newcmdline, "%s /OPT:[CURDIR=%s] %s %s", lpszPE, lpCurrentDirectory, szAppName, lpCommandLine);
1981 free(cmdline);
1982 cmdline = newcmdline;
1983 }
1984 else {
1985 char *newcmdline;
1986
1987 newcmdline = (char *)malloc(iNewCommandLineLength + 16);
1988 sprintf(newcmdline, "%s %s %s", lpszPE, szAppName, lpCommandLine);
1989 free(cmdline);
1990 cmdline = newcmdline;
1991 }
1992
1993 dprintf(("KERNEL32: CreateProcess starting [%s],[%s]",
1994 lpszExecutable,
1995 cmdline));
1996
1997 rc = O32_CreateProcess(lpszExecutable, (LPCSTR)cmdline,lpProcessAttributes,
1998 lpThreadAttributes, bInheritHandles, dwCreationFlags,
1999 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
2000 lpProcessInfo);
2001 }
2002 else
2003 if(fNEExe) {//16 bits windows app
2004 char *newcmdline;
2005
2006 newcmdline = (char *)malloc(strlen(szAppName) + strlen(cmdline) + 16);
2007 sprintf(newcmdline, "%s %s", szNELoader, szAppName, lpCommandLine);
2008 free(cmdline);
2009 cmdline = newcmdline;
2010 //Force Open32 to use DosStartSession (DosExecPgm won't do)
2011 dwCreationFlags |= CREATE_NEW_PROCESS_GROUP;
2012 rc = O32_CreateProcess(szNELoader, (LPCSTR)cmdline, lpProcessAttributes,
2013 lpThreadAttributes, bInheritHandles, dwCreationFlags,
2014 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
2015 lpProcessInfo);
2016 }
2017 else {//os/2 app??
2018 rc = O32_CreateProcess(szAppName, (LPCSTR)lpCommandLine, lpProcessAttributes,
2019 lpThreadAttributes, bInheritHandles, dwCreationFlags,
2020 lpEnvironment, lpCurrentDirectory, lpStartupInfo,
2021 lpProcessInfo);
2022 }
2023 if(rc == TRUE)
2024 {
2025 if (dwCreationFlags & DEBUG_PROCESS && pThreadDB != NULL)
2026 {
2027 if(pThreadDB->o.odin.pidDebuggee != 0)
2028 {
2029 // TODO: handle this
2030 dprintf(("KERNEL32: CreateProcess ERROR: This thread is already a debugger\n"));
2031 }
2032 else
2033 {
2034 pThreadDB->o.odin.pidDebuggee = lpProcessInfo->dwProcessId;
2035 OSLibStartDebugger((ULONG*)&pThreadDB->o.odin.pidDebuggee);
2036 }
2037 }
2038 else
2039 pThreadDB->o.odin.pidDebuggee = 0;
2040 }
2041 if(cmdline)
2042 free(cmdline);
2043
2044 if(lpProcessInfo)
2045 {
2046 lpProcessInfo->dwThreadId = MAKE_THREADID(lpProcessInfo->dwProcessId, lpProcessInfo->dwThreadId);
2047 dprintf(("KERNEL32: CreateProcess returned %d hPro:%x hThr:%x pid:%x tid:%x\n",
2048 rc, lpProcessInfo->hProcess, lpProcessInfo->hThread,
2049 lpProcessInfo->dwProcessId,lpProcessInfo->dwThreadId));
2050 }
2051 else
2052 dprintf(("KERNEL32: CreateProcess returned %d\n", rc));
2053 return(rc);
2054}
2055//******************************************************************************
2056//******************************************************************************
2057BOOL WIN32API CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
2058 PSECURITY_ATTRIBUTES lpProcessAttributes,
2059 PSECURITY_ATTRIBUTES lpThreadAttributes,
2060 BOOL bInheritHandles, DWORD dwCreationFlags,
2061 LPVOID lpEnvironment,
2062 LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
2063 LPPROCESS_INFORMATION lpProcessInfo)
2064{
2065 BOOL rc;
2066 char *astring1 = 0, *astring2 = 0, *astring3 = 0;
2067
2068 dprintf(("KERNEL32: CreateProcessW"));
2069 if(lpApplicationName)
2070 astring1 = UnicodeToAsciiString((LPWSTR)lpApplicationName);
2071 if(lpCommandLine)
2072 astring2 = UnicodeToAsciiString(lpCommandLine);
2073 if(lpCurrentDirectory)
2074 astring3 = UnicodeToAsciiString((LPWSTR)lpCurrentDirectory);
2075 rc = CreateProcessA(astring1, astring2, lpProcessAttributes, lpThreadAttributes,
2076 bInheritHandles, dwCreationFlags, lpEnvironment,
2077 astring3, (LPSTARTUPINFOA)lpStartupInfo,
2078 lpProcessInfo);
2079 if(astring3) FreeAsciiString(astring3);
2080 if(astring2) FreeAsciiString(astring2);
2081 if(astring1) FreeAsciiString(astring1);
2082 return(rc);
2083}
2084//******************************************************************************
2085//******************************************************************************
2086HINSTANCE WIN32API WinExec(LPCSTR lpCmdLine, UINT nCmdShow)
2087{
2088 STARTUPINFOA startinfo = {0};
2089 PROCESS_INFORMATION procinfo;
2090 DWORD rc;
2091 HINSTANCE hInstance;
2092
2093 dprintf(("KERNEL32: WinExec %s\n", lpCmdLine));
2094 startinfo.dwFlags = nCmdShow;
2095 if(CreateProcessA(NULL, (LPSTR)lpCmdLine, NULL, NULL, FALSE, 0, NULL, NULL,
2096 &startinfo, &procinfo) == FALSE)
2097 {
2098 hInstance = (HINSTANCE)GetLastError();
2099 if(hInstance >= 32) {
2100 hInstance = 11;
2101 }
2102 dprintf(("KERNEL32: WinExec failed with rc %d", hInstance));
2103 return hInstance;
2104 }
2105 //block until the launched app waits for input (or a timeout of 15 seconds)
2106 //TODO: Shouldn't call Open32, but the api in user32..
2107 if(fVersionWarp3) {
2108 Sleep(1000); //WaitForInputIdle not available in Warp 3
2109 }
2110 else {
2111 dprintf(("Calling WaitForInputIdle %x %d", procinfo.hProcess, 15000));
2112 rc = WaitForInputIdle(procinfo.hProcess, 15000);
2113#ifdef DEBUG
2114 if(rc != 0) {
2115 dprintf(("WinExec: WaitForInputIdle %x returned %x", procinfo.hProcess, rc));
2116 }
2117 else dprintf(("WinExec: WaitForInputIdle successfull"));
2118#endif
2119 }
2120 CloseHandle(procinfo.hThread);
2121 CloseHandle(procinfo.hProcess);
2122 return 33;
2123}
2124//******************************************************************************
2125//DWORD idAttach; /* thread to attach */
2126//DWORD idAttachTo; /* thread to attach to */
2127//BOOL fAttach; /* attach or detach */
2128//******************************************************************************
2129BOOL WIN32API AttachThreadInput(DWORD idAttach, DWORD idAttachTo, BOOL fAttach)
2130{
2131 dprintf(("USER32: AttachThreadInput, not implemented\n"));
2132 return(TRUE);
2133}
2134//******************************************************************************
2135//******************************************************************************
2136DWORD WIN32API WaitForInputIdle(HANDLE hProcess, DWORD dwTimeOut)
2137{
2138 dprintf(("USER32: WaitForInputIdle %x %d\n", hProcess, dwTimeOut));
2139
2140 if(fVersionWarp3) {
2141 Sleep(1000);
2142 return 0;
2143 }
2144 else return O32_WaitForInputIdle(hProcess, dwTimeOut);
2145}
2146/**********************************************************************
2147 * LoadModule (KERNEL32.499)
2148 *
2149 * Wine: 20000909
2150 *
2151 * Copyright 1995 Alexandre Julliard
2152 */
2153HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock )
2154{
2155 LOADPARAMS *params = (LOADPARAMS *)paramBlock;
2156 PROCESS_INFORMATION info;
2157 STARTUPINFOA startup;
2158 HINSTANCE hInstance;
2159 LPSTR cmdline, p;
2160 char filename[MAX_PATH];
2161 BYTE len;
2162
2163 dprintf(("LoadModule %s %x", name, paramBlock));
2164
2165 if (!name) return ERROR_FILE_NOT_FOUND;
2166
2167 if (!SearchPathA( NULL, name, ".exe", sizeof(filename), filename, NULL ) &&
2168 !SearchPathA( NULL, name, NULL, sizeof(filename), filename, NULL ))
2169 return GetLastError();
2170
2171 len = (BYTE)params->lpCmdLine[0];
2172 if (!(cmdline = (LPSTR)HeapAlloc( GetProcessHeap(), 0, strlen(filename) + len + 2 )))
2173 return ERROR_NOT_ENOUGH_MEMORY;
2174
2175 strcpy( cmdline, filename );
2176 p = cmdline + strlen(cmdline);
2177 *p++ = ' ';
2178 memcpy( p, params->lpCmdLine + 1, len );
2179 p[len] = 0;
2180
2181 memset( &startup, 0, sizeof(startup) );
2182 startup.cb = sizeof(startup);
2183 if (params->lpCmdShow)
2184 {
2185 startup.dwFlags = STARTF_USESHOWWINDOW;
2186 startup.wShowWindow = params->lpCmdShow[1];
2187 }
2188
2189 if (CreateProcessA( filename, cmdline, NULL, NULL, FALSE, 0,
2190 params->lpEnvAddress, NULL, &startup, &info ))
2191 {
2192 /* Give 15 seconds to the app to come up */
2193 if ( WaitForInputIdle ( info.hProcess, 15000 ) == 0xFFFFFFFF )
2194 dprintf(("ERROR: WaitForInputIdle failed: Error %ld\n", GetLastError() ));
2195 hInstance = 33;
2196 /* Close off the handles */
2197 CloseHandle( info.hThread );
2198 CloseHandle( info.hProcess );
2199 }
2200 else if ((hInstance = GetLastError()) >= 32)
2201 {
2202 dprintf(("ERROR: Strange error set by CreateProcess: %d\n", hInstance ));
2203 hInstance = 11;
2204 }
2205
2206 HeapFree( GetProcessHeap(), 0, cmdline );
2207 return hInstance;
2208}
2209//******************************************************************************
2210//******************************************************************************
2211FARPROC WIN32API GetProcAddress(HMODULE hModule, LPCSTR lpszProc)
2212{
2213 Win32ImageBase *winmod;
2214 FARPROC proc;
2215 ULONG ulAPIOrdinal;
2216
2217 if(hModule == 0 || hModule == -1 || (WinExe && hModule == WinExe->getInstanceHandle())) {
2218 winmod = WinExe;
2219 }
2220 else winmod = (Win32ImageBase *)Win32DllBase::findModule((HINSTANCE)hModule);
2221
2222 if(winmod) {
2223 ulAPIOrdinal = (ULONG)lpszProc;
2224 if (ulAPIOrdinal <= 0x0000FFFF) {
2225 proc = (FARPROC)winmod->getApi((int)ulAPIOrdinal);
2226 }
2227 else proc = (FARPROC)winmod->getApi((char *)lpszProc);
2228 if(proc == 0) {
2229#ifdef DEBUG
2230 if(ulAPIOrdinal <= 0x0000FFFF) {
2231 dprintf(("GetProcAddress %x %x not found!", hModule, ulAPIOrdinal));
2232 }
2233 else dprintf(("GetProcAddress %x %s not found!", hModule, lpszProc));
2234#endif
2235 SetLastError(ERROR_PROC_NOT_FOUND);
2236 }
2237 if(HIWORD(lpszProc))
2238 dprintf(("KERNEL32: GetProcAddress %s from %X returned %X\n", lpszProc, hModule, proc));
2239 else dprintf(("KERNEL32: GetProcAddress %x from %X returned %X\n", lpszProc, hModule, proc));
2240
2241 SetLastError(ERROR_SUCCESS);
2242 return proc;
2243 }
2244 proc = (FARPROC)OSLibDosGetProcAddress(hModule, lpszProc);
2245 if(HIWORD(lpszProc))
2246 dprintf(("KERNEL32: GetProcAddress %s from %X returned %X\n", lpszProc, hModule, proc));
2247 else dprintf(("KERNEL32: GetProcAddress %x from %X returned %X\n", lpszProc, hModule, proc));
2248 SetLastError(ERROR_SUCCESS);
2249 return(proc);
2250}
2251//******************************************************************************
2252//Retrieve the version
2253//******************************************************************************
2254BOOL SYSTEM GetVersionStruct(char *lpszModName, char *verstruct, ULONG bufLength)
2255{
2256 Win32ImageBase *winimage;
2257 HINSTANCE hDll;
2258 BOOL rc = FALSE;
2259
2260 dprintf(("GetVersionStruct of module %s %x %d", lpszModName, verstruct, bufLength));
2261 if(verstruct == NULL) {
2262 SetLastError(ERROR_INVALID_PARAMETER);
2263 return FALSE;
2264 }
2265 if (WinExe != NULL && WinExe->matchModName(lpszModName)) {
2266 return WinExe->getVersionStruct(verstruct, bufLength);
2267 }
2268 hDll = LoadLibraryExA(lpszModName, 0, LOAD_LIBRARY_AS_DATAFILE);
2269 if(hDll == 0) {
2270 dprintf(("ERROR: GetVersionStruct: Unable to load module!!"));
2271 return 0;
2272 }
2273 winimage = (Win32ImageBase *)Win32DllBase::findModule(hDll);
2274 if(winimage != NULL) {
2275 rc = winimage->getVersionStruct(verstruct, bufLength);
2276 }
2277 else {
2278 dprintf(("GetVersionStruct; just loaded dll %s, but can't find it now!", lpszModName));
2279//// DebugInt3();
2280 }
2281 FreeLibrary(hDll);
2282 return rc;
2283}
2284//******************************************************************************
2285//******************************************************************************
2286ULONG SYSTEM GetVersionSize(char *lpszModName)
2287{
2288 Win32ImageBase *winimage;
2289 HINSTANCE hDll;
2290 ULONG size = 0;
2291
2292 dprintf(("GetVersionSize of %s", lpszModName));
2293 if (WinExe != NULL && WinExe->matchModName(lpszModName)) {
2294 return WinExe->getVersionSize();
2295 }
2296
2297 hDll = LoadLibraryExA(lpszModName, 0, LOAD_LIBRARY_AS_DATAFILE);
2298 if(hDll == 0) {
2299 dprintf(("ERROR: GetVersionStruct: Unable to load module!!"));
2300 return 0;
2301 }
2302 winimage = (Win32ImageBase *)Win32DllBase::findModule(hDll);
2303 if(winimage != NULL) {
2304 size = winimage->getVersionSize();
2305 }
2306 else {
2307 dprintf(("GetVersionSize; just loaded dll %s, but can't find it now!", lpszModName));
2308//// DebugInt3();
2309 }
2310 FreeLibrary(hDll);
2311 return size;
2312}
2313//******************************************************************************
2314//******************************************************************************
2315BOOL WIN32API DisableThreadLibraryCalls(HMODULE hModule)
2316{
2317 Win32DllBase *winmod;
2318 FARPROC proc;
2319 ULONG ulAPIOrdinal;
2320
2321 winmod = Win32DllBase::findModule((HINSTANCE)hModule);
2322 if(winmod)
2323 {
2324 // don't call ATTACH/DETACH thread functions in DLL
2325 winmod->disableThreadLibraryCalls();
2326 return TRUE;
2327 }
2328 else
2329 {
2330 // raise error condition
2331 SetLastError(ERROR_INVALID_HANDLE);
2332 return FALSE;
2333 }
2334}
2335//******************************************************************************
2336//******************************************************************************
Note: See TracBrowser for help on using the repository browser.