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

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

logging updates

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