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

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

improvement of profiler

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