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

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

allow os/2 dll loading for odin32 apps

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