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

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

Fix: return code for GetModuleHandleA(null) in ODIN32-LX-environment

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