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

Last change on this file since 8921 was 8921, checked in by sandervl, 23 years ago

terminate & resume threads that are suspended when ExitProcess is called

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