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

Last change on this file since 6831 was 6831, checked in by phaller, 24 years ago

.

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