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

Last change on this file since 4236 was 4236, checked in by bird, 25 years ago

Command line string rewrite.

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