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

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

Round stack top & bottom (TIB) to page boundary

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