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

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

thread linking + create TEB before thread creation

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