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

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

Do not use imports not available in Warp 3's PMWINX (WaitForInputIdle)

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