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

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

Copyright.

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