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

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

KSO: Console Ctrl Handlers updates; GetFileType on std files doesn't always return TYPE_CHAR; Enable writing to STDERRconodin32.cpp

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