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

Last change on this file since 6468 was 6468, checked in by sandervl, 24 years ago

CreateProcess & memory map fixes

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