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

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

added ODIN perfview profiler

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