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

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

Create event semaphore during TEB setup. Used for Post(Thread)Message in combination with MsgWaitForMultipleObjects

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