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

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

hard disk access updates & fixes

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