source: trunk/src/kernel32/windlllx.cpp@ 10304

Last change on this file since 10304 was 10304, checked in by sandervl, 22 years ago

compile fix

File size: 14.9 KB
Line 
1/* $Id: windlllx.cpp,v 1.28 2003-10-28 10:42:40 sandervl Exp $ */
2
3/*
4 * Win32 LX Dll class (compiled in OS/2 using Odin32 api)
5 *
6 * Copyright 1999-2000 Sander van Leeuwen (sandervl@xs4all.nl)
7 *
8 * TODO: Unloading of dlls probably needs to be fixed due to OS/2 bug
9 * (wrong unload order of dlls)
10 *
11 * Project Odin Software License can be found in LICENSE.TXT
12 *
13 */
14#define INCL_DOSFILEMGR /* File Manager values */
15#define INCL_DOSERRORS /* DOS Error values */
16#define INCL_DOSPROCESS /* DOS Process values */
17#define INCL_DOSMODULEMGR
18#define INCL_DOSMISC /* DOS Miscellanous values */
19#define INCL_WIN
20#include <os2wrap.h> //Odin32 OS/2 api wrappers
21#include <os2newapi.h>
22#include <stdio.h>
23#include <string.h>
24#include <stdlib.h>
25#include <iostream.h>
26#include <fstream.h>
27#include <misc.h>
28#include <win32type.h>
29#include <windllbase.h>
30#include <windlllx.h>
31#include "winexepe2lx.h"
32#include "winexepeldr.h"
33#include <odinlx.h>
34#include <wprocess.h>
35#include "oslibmisc.h"
36#include <custombuild.h>
37
38#include <exe386.h>
39
40#define DBG_LOCALLOG DBG_windlllx
41#include "dbglocal.h"
42
43/*******************************************************************************
44* Global Variables *
45*******************************************************************************/
46char *lpszCustomDllName = NULL;
47char *lpszCustomExportPrefix = NULL;
48ULONG dwOrdinalBase = 0;
49
50/**
51 * FreeLibrary callback for LX Dlls, it's call only when the library is actually
52 * being unloaded.
53 * Maintained by ODIN_SetLxDllUnLoadCallback().
54 */
55PFNLXDLLUNLOAD pfnLxDllUnLoadCallback = NULL;
56
57//******************************************************************************
58//******************************************************************************
59void WIN32API SetCustomBuildName(char *lpszName, PIMAGE_FILE_HEADER pfh)
60
61{
62 lpszCustomDllName = lpszName;
63}
64//******************************************************************************
65//Create LX Dll object and send process attach message
66//System dlls set EntryPoint to 0
67//Parameters:
68// HINSTANCE hInstance - OS/2 module handle
69// WIN32DLLENTRY EntryPoint - Win32 dll entrypoint address
70// PVOID pResData - pointer to win32 resource data
71// DWORD MajorImageVersion - major image/os version (for fake win32 header)
72// DWORD MinorImageVersion - minor image/os version (for fake win32 header)
73// DWORD Subsystem - subsystem type (for fake win32 header)
74// (IMAGE_SUBSYSTEM_WINDOWS_CUI/IMAGE_SUBSYSTEM_WINDOWS_GUI)
75//
76//Returns: Odin32 module handle
77//******************************************************************************
78DWORD WIN32API RegisterLxDll(HINSTANCE hInstance, WIN32DLLENTRY EntryPoint,
79 PVOID pResData,
80 DWORD MajorImageVersion,
81 DWORD MinorImageVersion,
82 DWORD Subsystem)
83{
84 APIRET rc;
85 Win32LxDll *windll;
86 Win32DllBase *windlldep;
87 char szFileName[CCHMAXPATH], szErrName[CCHMAXPATH];
88
89 if(!lpszCustomDllName) {
90 if(OSLibGetDllName(hInstance, szFileName, sizeof(szFileName)) == FALSE) {
91 dprintf(("ERROR: RegisterLxDll: OSLibGetDllName %x failed!!", hInstance));
92 return 0;
93 }
94 dprintf(("RegisterLxDll %x %s", hInstance, szFileName));
95 //Make sure DosLoadModule is called at least once for a dll (to make sure
96 //OS/2 doesn't unload the dll when it's still needed)
97 rc = DosLoadModule(szErrName, sizeof(szErrName), szFileName, &hInstance);
98 if(rc != 0) {
99 dprintf(("ERROR: RegisterLxDll: DosLoadModule %s failed (rc=%d)!!", szFileName, rc));
100 return 0;
101 }
102 }
103 windll = new Win32LxDll(hInstance, EntryPoint, pResData, MajorImageVersion,
104 MinorImageVersion, Subsystem);
105 if(windll == NULL) {
106 dprintf(("RegisterLxDll: windll == NULL!!!"));
107 return 0;
108 }
109 //clear name override in case dll init loads another dll
110 lpszCustomDllName = NULL;
111
112 if(!fPeLoader) {
113 windll->AddRef();
114
115 if(windll->attachProcess() == 0)
116 return 0;
117
118 return windll->getInstanceHandle();
119 }
120 IMAGE_DOS_HEADER doshdr;
121 struct e32_exe lxhdr;
122 ULONG offset;
123 char modulename[CCHMAXPATH];
124 char modsize;
125 int i;
126
127 //SvL: This code reads the import name table of the dll to get the dependencies
128 // on other dlls.
129 //DosQueryHeaderInfo is an undocumented api, but works very well.
130 //(no need to save FS here as we'll return to OS/2 immediately)
131 rc = DosQueryHeaderInfo(hInstance, 0, &doshdr, sizeof(IMAGE_DOS_HEADER), QHINF_READFILE);
132 if(rc) {
133 goto hdrerror;
134 }
135 rc = DosQueryHeaderInfo(hInstance, doshdr.e_lfanew, &lxhdr, sizeof(e32_exe), QHINF_READFILE);
136 if(rc) {
137 goto hdrerror;
138 }
139 offset = doshdr.e_lfanew + lxhdr.e32_impmod;
140 for(i=0;i<lxhdr.e32_impmodcnt;i++) {
141 rc = DosQueryHeaderInfo(hInstance, offset, &modsize, 1, QHINF_READFILE);
142 if(rc) {
143 goto hdrerror;
144 }
145 rc = DosQueryHeaderInfo(hInstance, offset+1, &modulename, min(modsize, sizeof(modulename)), QHINF_READFILE);
146 if(rc) {
147 goto hdrerror;
148 }
149 modulename[modsize] = 0;
150 windlldep = Win32DllBase::findModule(modulename, TRUE);
151 if(windlldep && strcmp(windlldep->getModuleName(), windll->getModuleName())) {
152 dprintf(("RegisterLxDll: Add dependency %s -> %s", windll->getModuleName(), modulename));
153 windll->addDependency(windlldep);
154 }
155 else dprintf(("HARMLESS WARNING: Can't find dll %s referenced by %s", modulename, windll->getModuleName()));
156
157 offset += modsize + 1;
158 }
159#ifdef HACK_NEVER_UNLOAD_LX_DLLS
160 //HACK ALERT!!
161 //This makes sure the LX dll never gets unloaded.
162 //Necessary since unloading doesn't work due to dependencies on dlls
163 //with exitlist handlers.
164 windll->AddRef();
165#endif
166 return windll->getInstanceHandle();
167
168hdrerror:
169 dprintf(("DosQueryHeaderInfo returned %d", rc));
170 return windll->getInstanceHandle();
171}
172//******************************************************************************
173//Destroy LX Dll object
174//******************************************************************************
175BOOL WIN32API UnregisterLxDll(HINSTANCE hInstance)
176{
177 Win32DllBase *windll;
178
179 //Don't proceed for pe2lx/win32k (os/2 dll unload dependency bug)
180 //Don't do it either after ExitProcess has been called
181 if(!fPeLoader || WinExe == NULL)
182 return TRUE;
183
184 windll = Win32DllBase::findModule(hInstance);
185 if(!windll) {
186 dprintf(("UnregisterLxDll: Can't find dll with handle %x (already deleted)", hInstance));
187 return TRUE; //already deleted by Win32LxDll::Release
188 }
189 dprintf(("UnregisterLxDll %s", windll->getModuleName()));
190 //This can only happen for LX dependencies (i.e. wininet loads wsock32)
191 delete windll;
192 return TRUE;
193}
194//******************************************************************************
195//******************************************************************************
196Win32LxDll::Win32LxDll(HINSTANCE hInstance, WIN32DLLENTRY EntryPoint, PVOID pResData,
197 DWORD MajorImageVersion, DWORD MinorImageVersion,
198 DWORD Subsystem)
199 : Win32ImageBase(hInstance),
200 Win32LxImage(hInstance, pResData),
201 Win32DllBase(hInstance, EntryPoint)
202{
203 this->MajorImageVersion = MajorImageVersion;
204 this->MinorImageVersion = MinorImageVersion;
205 this->Subsystem = Subsystem;
206
207 if(EntryPoint == NULL) {
208 fSkipThreadEntryCalls = TRUE;
209 fAttachedToProcess = TRUE;
210 }
211 hinstanceOS2 = hInstance;
212 //new win32 instance handle must be pointer to PE header
213 hinstance = (HINSTANCE)buildHeader(MajorImageVersion, MinorImageVersion,
214 Subsystem);
215 dprintf(("Fake PE header %x for dll %s", hinstance, getModuleName()));
216}
217//******************************************************************************
218//******************************************************************************
219Win32LxDll::~Win32LxDll()
220{
221}
222//******************************************************************************
223//Returns reference count or -1 if load failed (PE loader only!)
224//******************************************************************************
225#ifdef DEBUG
226ULONG Win32LxDll::AddRef(char *parentname)
227#else
228ULONG Win32LxDll::AddRef()
229#endif
230{
231 Win32DllBase *dll;
232 QueueItem *item;
233 ULONG ret;
234
235#ifdef DEBUG
236 ret = Win32DllBase::AddRef(parentname);
237#else
238 ret = Win32DllBase::AddRef();
239#endif
240
241 if(!fPeLoader)
242 return ret;
243
244 if(referenced == 1)
245 {
246 item = loadedDlls.Head();
247 while(item) {
248 dll = (Win32DllBase *)loadedDlls.getItem(item);
249 if(dll == NULL) {
250 dprintf(("ERROR: Win32DllBase::AddRef: dll item == NULL!!"));
251 DebugInt3();
252 return -1;
253 }
254#ifdef DEBUG
255 dll->AddRef(getModuleName());
256#else
257 dll->AddRef();
258#endif
259 item = loadedDlls.getNext(item);
260 }
261 if(attachProcess() == 0) {
262 dprintf(("WARNING: Dll %s refused to be loaded; aborting", getName()));
263 return -1;
264 }
265 }
266 return ret;
267}
268//******************************************************************************
269//******************************************************************************
270ULONG Win32LxDll::Release()
271{
272 HINSTANCE hinst = hinstanceOS2;
273 HINSTANCE hinstOdin = hinstance;
274 WIN32DLLENTRY EntryPointTmp = dllEntryPoint;
275 PVOID pResDataTmp = (PVOID)pResRootDir;
276 DWORD MajorImageVersionTmp = MajorImageVersion;
277 DWORD MinorImageVersionTmp = MinorImageVersion;
278 DWORD SubsystemTmp = Subsystem;
279 BOOL fNoUnload = fDisableUnload; //only set for kernel32.dll
280 BOOL fDynLoaded = isDynamicLib();
281 ULONG ret;
282 APIRET rc;
283
284 ret = Win32DllBase::Release();
285
286 /** @sketch
287 * If this module is not unreference and it was loaded using LoadLibrary() then
288 * call the custombuild callback if present.
289 * The callback should call UnRegisterLxDll().
290 * Endif
291 *
292 * @remark
293 * #ifdef HACK_NEVER_UNLOAD_LX_DLLS
294 * This will never be called!
295 * #endif
296 *
297 * @todo: call pfnLxDllLoadCallback if DosFreeModule failes.
298 * It's not implemented because it's complex and at the moment we will
299 * never actually get here.
300 * So, this callback is here just as a reminder eventhough it's working..
301 */
302 if (!ret && fDynLoaded && pfnLxDllUnLoadCallback)
303 {
304 pfnLxDllUnLoadCallback(hinstanceOS2, hinstance);
305 }
306
307 if (ret == 0 && !fNoUnload) {//only set for kernel32.dll (fDisableUnload)
308 //DosFreeModule sends a termination message to the dll.
309 //The LX dll informs us when it's removed (UnregisterDll call)
310 rc = DosFreeModule(hinst);
311 if(rc) {
312 dprintf(("Win32LxDll::Release: DosFreeModule %x returned %d", hinst, rc));
313 if(rc == ERROR_INVALID_ACCESS && !fExitProcess)
314 {
315 #ifndef HACK_NEVER_UNLOAD_LX_DLLS
316 #error @todo: call pfnLxDllLoadCallback and let it do the registering if it did that on the initial load..
317 #endif
318 //Dll refused to unload because it has an active exitlist handler
319 //or depends on a dll that registered an exitlist handler
320 //In this case the handle remains valid and the entrypoint of
321 //the dll is NOT called for DLL_PROCESS_DETACH
322 //WORKAROUND: Re-register the dll so future LoadLibrary calls
323 // don't fail!
324 dprintf(("WORKAROUND: Re-register the dll so future LoadLibrary calls don't fail!"));
325 RegisterLxDll(hinst, EntryPointTmp, pResDataTmp,
326 MajorImageVersionTmp,
327 MinorImageVersionTmp,
328 SubsystemTmp);
329
330 /* OS/2 dll, system dll, converted dll or win32k took care of it. */
331 Win32LxDll *pModule = Win32LxDll::findModuleByOS2Handle(hinst);
332 if(pModule)
333 {
334 pModule->setDllHandleOS2(hinst);
335 if(fPeLoader)
336 {
337 if(pModule->AddRef() == -1) {//-1 -> load failed (attachProcess)
338 dprintf(("ERROR Dll refused to be loaded; aborting"));
339 DebugInt3();
340 delete pModule;
341 return 0;
342 }
343 }
344 pModule->incDynamicLib();
345 }
346 else DebugInt3();
347 }
348 }
349 }
350 return(ret);
351}
352//******************************************************************************
353//******************************************************************************
354BOOL Win32LxDll::isPe2LxDll() const
355{
356 return FALSE;
357}
358//******************************************************************************
359//******************************************************************************
360BOOL Win32LxDll::isLxDll() const
361{
362 return TRUE;
363}
364//******************************************************************************
365//******************************************************************************
366void Win32LxDll::setDllHandleOS2(HINSTANCE hInstanceOS2)
367{
368 //Loaded with LoadLibrary(Ex); no need for a 2nd DosLoadModule
369 //Dlls that are indirectly loaded (i.e. GDI32->KERNEL32 dependancy) need
370 //this additional DosLoadModule (and setDllHandleOS2 isn't called for those)
371 if(this->hinstanceOS2) {
372 DosFreeModule(this->hinstanceOS2);
373 }
374 this->hinstanceOS2 = hInstanceOS2;
375}
376//******************************************************************************
377//******************************************************************************
378Win32LxDll *Win32LxDll::findModuleByOS2Handle(HINSTANCE hinstance)
379{
380 dlllistmutex.enter();
381
382 Win32DllBase *mod = Win32DllBase::getFirst();
383 while (mod != NULL)
384 {
385 if (mod->isLxDll())
386 {
387 Win32LxDll *lxdll = (Win32LxDll *)mod;
388 if (lxdll->hinstanceOS2 == hinstance)
389 {
390 dlllistmutex.leave();
391 return(lxdll);
392 }
393 }
394 mod = mod->getNext();
395 }
396 dlllistmutex.leave();
397 return(NULL);
398}
399//******************************************************************************
400//******************************************************************************
401
402/**
403 * Custombuild API for registering a callback for LX Dll loading thru LoadLibrary*().
404 * @returns Success indicator.
405 * @param pfn Pointer to callback.
406 * NULL if callback is deregistered.
407 */
408BOOL WIN32API ODIN_SetLxDllUnLoadCallback(PFNLXDLLUNLOAD pfn)
409{
410 pfnLxDllUnLoadCallback = pfn;
411 return TRUE;
412}
413
Note: See TracBrowser for help on using the repository browser.