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

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

priority updates/changes

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