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

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

thread handler call workaround for app bugs + GetBinaryTypeA/W port

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