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

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

some minor updates

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