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

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

* empty log message *

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