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

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

.

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