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

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

fixed GetCurrentThreadId

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