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

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

fix for lx dll unload fix

File size: 13.1 KB
Line 
1/* $Id: windlllx.cpp,v 1.25 2002-05-21 14: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
37#include <exe386.h>
38
39#define DBG_LOCALLOG DBG_windlllx
40#include "dbglocal.h"
41
42char *lpszCustomDllName = NULL;
43ULONG dwOrdinalBase = 0;
44
45//******************************************************************************
46//******************************************************************************
47void WIN32API SetCustomBuildName(char *lpszName, DWORD ordinalbase)
48{
49 lpszCustomDllName = lpszName;
50 dwOrdinalBase = ordinalbase;
51}
52//******************************************************************************
53//Create LX Dll object and send process attach message
54//System dlls set EntryPoint to 0
55//Parameters:
56// HINSTANCE hInstance - OS/2 module handle
57// WIN32DLLENTRY EntryPoint - Win32 dll entrypoint address
58// PVOID pResData - pointer to win32 resource data
59// DWORD MajorImageVersion - major image/os version (for fake win32 header)
60// DWORD MinorImageVersion - minor image/os version (for fake win32 header)
61// DWORD Subsystem - subsystem type (for fake win32 header)
62// (IMAGE_SUBSYSTEM_WINDOWS_CUI/IMAGE_SUBSYSTEM_WINDOWS_GUI)
63//
64//Returns: Odin32 module handle
65//******************************************************************************
66DWORD WIN32API RegisterLxDll(HINSTANCE hInstance, WIN32DLLENTRY EntryPoint,
67 PVOID pResData,
68 DWORD MajorImageVersion,
69 DWORD MinorImageVersion,
70 DWORD Subsystem)
71{
72 APIRET rc;
73 Win32LxDll *windll;
74 Win32DllBase *windlldep;
75 char szFileName[CCHMAXPATH], szErrName[CCHMAXPATH];
76
77 if(!lpszCustomDllName) {
78 if(OSLibGetDllName(hInstance, szFileName, sizeof(szFileName)) == FALSE) {
79 dprintf(("ERROR: RegisterLxDll: OSLibGetDllName %x failed!!", hInstance));
80 return 0;
81 }
82 dprintf(("RegisterLxDll %x %s", hInstance, szFileName));
83 //Make sure DosLoadModule is called at least once for a dll (to make sure
84 //OS/2 doesn't unload the dll when it's still needed)
85 rc = DosLoadModule(szErrName, sizeof(szErrName), szFileName, &hInstance);
86 if(rc != 0) {
87 dprintf(("ERROR: RegisterLxDll: DosLoadModule %s failed (rc=%d)!!", szFileName, rc));
88 return 0;
89 }
90 }
91 windll = new Win32LxDll(hInstance, EntryPoint, pResData, MajorImageVersion,
92 MinorImageVersion, Subsystem);
93 if(windll == NULL) {
94 dprintf(("RegisterLxDll: windll == NULL!!!"));
95 return 0;
96 }
97 //clear name override in case dll init loads another dll
98 lpszCustomDllName = NULL;
99
100 if(!fPeLoader) {
101 windll->AddRef();
102
103 if(windll->attachProcess() == 0)
104 return 0;
105
106 return windll->getInstanceHandle();
107 }
108 IMAGE_DOS_HEADER doshdr;
109 struct e32_exe lxhdr;
110 ULONG offset;
111 char modulename[CCHMAXPATH];
112 char modsize;
113 int i;
114
115 //SvL: This code reads the import name table of the dll to get the dependencies
116 // on other dlls.
117 //DosQueryHeaderInfo is an undocumented api, but works very well.
118 //(no need to save FS here as we'll return to OS/2 immediately)
119 rc = DosQueryHeaderInfo(hInstance, 0, &doshdr, sizeof(IMAGE_DOS_HEADER), QHINF_READFILE);
120 if(rc) {
121 goto hdrerror;
122 }
123 rc = DosQueryHeaderInfo(hInstance, doshdr.e_lfanew, &lxhdr, sizeof(e32_exe), QHINF_READFILE);
124 if(rc) {
125 goto hdrerror;
126 }
127 offset = doshdr.e_lfanew + lxhdr.e32_impmod;
128 for(i=0;i<lxhdr.e32_impmodcnt;i++) {
129 rc = DosQueryHeaderInfo(hInstance, offset, &modsize, 1, QHINF_READFILE);
130 if(rc) {
131 goto hdrerror;
132 }
133 rc = DosQueryHeaderInfo(hInstance, offset+1, &modulename, min(modsize, sizeof(modulename)), QHINF_READFILE);
134 if(rc) {
135 goto hdrerror;
136 }
137 modulename[modsize] = 0;
138 windlldep = Win32DllBase::findModule(modulename, TRUE);
139 if(windlldep && strcmp(windlldep->getModuleName(), windll->getModuleName())) {
140 dprintf(("RegisterLxDll: Add dependency %s -> %s", windll->getModuleName(), modulename));
141 windll->addDependency(windlldep);
142 }
143 else dprintf(("HARMLESS WARNING: Can't find dll %s referenced by %s", modulename, windll->getModuleName()));
144
145 offset += modsize + 1;
146 }
147#ifdef HACK_NEVER_UNLOAD_LX_DLLS
148 //HACK ALERT!!
149 //This makes sure the LX dll never gets unloaded.
150 //Necessary since unloading doesn't work due to dependencies on dlls
151 //with exitlist handlers.
152 windll->AddRef();
153#endif
154 return windll->getInstanceHandle();
155
156hdrerror:
157 dprintf(("DosQueryHeaderInfo returned %d", rc));
158 return windll->getInstanceHandle();
159}
160//******************************************************************************
161//Destroy LX Dll object
162//******************************************************************************
163BOOL WIN32API UnregisterLxDll(HINSTANCE hInstance)
164{
165 Win32DllBase *windll;
166
167 //Don't proceed for pe2lx/win32k (os/2 dll unload dependency bug)
168 //Don't do it either after ExitProcess has been called
169 if(!fPeLoader || WinExe == NULL)
170 return TRUE;
171
172 windll = Win32DllBase::findModule(hInstance);
173 if(!windll) {
174 dprintf(("UnregisterLxDll: Can't find dll with handle %x (already deleted)", hInstance));
175 return TRUE; //already deleted by Win32LxDll::Release
176 }
177 dprintf(("UnregisterLxDll %s", windll->getModuleName()));
178 //This can only happen for LX dependencies (i.e. wininet loads wsock32)
179 delete windll;
180 return TRUE;
181}
182//******************************************************************************
183//******************************************************************************
184Win32LxDll::Win32LxDll(HINSTANCE hInstance, WIN32DLLENTRY EntryPoint, PVOID pResData,
185 DWORD MajorImageVersion, DWORD MinorImageVersion,
186 DWORD Subsystem)
187 : Win32ImageBase(hInstance),
188 Win32LxImage(hInstance, pResData),
189 Win32DllBase(hInstance, EntryPoint)
190{
191 this->MajorImageVersion = MajorImageVersion;
192 this->MinorImageVersion = MinorImageVersion;
193 this->Subsystem = Subsystem;
194
195 if(EntryPoint == NULL) {
196 fSkipThreadEntryCalls = TRUE;
197 fAttachedToProcess = TRUE;
198 }
199 hinstanceOS2 = hInstance;
200 //new win32 instance handle must be pointer to PE header
201 hinstance = (HINSTANCE)buildHeader(MajorImageVersion, MinorImageVersion,
202 Subsystem);
203 dprintf(("Fake PE header %x for dll %s", hinstance, getModuleName()));
204}
205//******************************************************************************
206//******************************************************************************
207Win32LxDll::~Win32LxDll()
208{
209}
210//******************************************************************************
211//Returns reference count or -1 if load failed (PE loader only!)
212//******************************************************************************
213#ifdef DEBUG
214ULONG Win32LxDll::AddRef(char *parentname)
215#else
216ULONG Win32LxDll::AddRef()
217#endif
218{
219 Win32DllBase *dll;
220 QueueItem *item;
221 ULONG ret;
222
223#ifdef DEBUG
224 ret = Win32DllBase::AddRef(parentname);
225#else
226 ret = Win32DllBase::AddRef();
227#endif
228
229 if(!fPeLoader)
230 return ret;
231
232 if(referenced == 1)
233 {
234 item = loadedDlls.Head();
235 while(item) {
236 dll = (Win32DllBase *)loadedDlls.getItem(item);
237 if(dll == NULL) {
238 dprintf(("ERROR: Win32DllBase::AddRef: dll item == NULL!!"));
239 DebugInt3();
240 return -1;
241 }
242#ifdef DEBUG
243 dll->AddRef(getModuleName());
244#else
245 dll->AddRef();
246#endif
247 item = loadedDlls.getNext(item);
248 }
249 if(attachProcess() == 0) {
250 dprintf(("WARNING: Dll %s refused to be loaded; aborting", getName()));
251 return -1;
252 }
253 }
254 return ret;
255}
256//******************************************************************************
257//******************************************************************************
258ULONG Win32LxDll::Release()
259{
260 HINSTANCE hinst;
261 WIN32DLLENTRY EntryPointTmp = dllEntryPoint;
262 PVOID pResDataTmp = (PVOID)pResRootDir;
263 DWORD MajorImageVersionTmp = MajorImageVersion;
264 DWORD MinorImageVersionTmp = MinorImageVersion;
265 DWORD SubsystemTmp = Subsystem;
266 ULONG ret;
267 APIRET rc;
268 BOOL fNoUnload = fDisableUnload; //only set for kernel32.dll
269 Win32LxDll *pModule;
270
271 hinst = hinstanceOS2;
272 ret = Win32DllBase::Release();
273 if(ret == 0 && !fNoUnload) {//only set for kernel32.dll (fDisableUnload)
274 //DosFreeModule sends a termination message to the dll.
275 //The LX dll informs us when it's removed (UnregisterDll call)
276 rc = DosFreeModule(hinst);
277 if(rc) {
278 dprintf(("Win32LxDll::Release: DosFreeModule %x returned %d", hinst, rc));
279 if(rc == ERROR_INVALID_ACCESS && !fExitProcess)
280 {
281 //Dll refused to unload because it has an active exitlist handler
282 //or depends on a dll that registered an exitlist handler
283 //In this case the handle remains valid and the entrypoint of
284 //the dll is NOT called for DLL_PROCESS_DETACH
285 //WORKAROUND: Re-register the dll so future LoadLibrary calls
286 // don't fail!
287 dprintf(("WORKAROUND: Re-register the dll so future LoadLibrary calls don't fail!"));
288 RegisterLxDll(hinst, EntryPointTmp, pResDataTmp,
289 MajorImageVersionTmp,
290 MinorImageVersionTmp,
291 SubsystemTmp);
292
293 /* OS/2 dll, system dll, converted dll or win32k took care of it. */
294 pModule = Win32LxDll::findModuleByOS2Handle(hinst);
295 if(pModule)
296 {
297 pModule->setDllHandleOS2(hinst);
298 if(fPeLoader)
299 {
300 if(pModule->AddRef() == -1) {//-1 -> load failed (attachProcess)
301 dprintf(("ERROR Dll refused to be loaded; aborting"));
302 DebugInt3();
303 delete pModule;
304 return 0;
305 }
306 }
307 pModule->incDynamicLib();
308 }
309 else DebugInt3();
310 }
311 }
312 }
313 return(ret);
314}
315//******************************************************************************
316//******************************************************************************
317BOOL Win32LxDll::isPe2LxDll() const
318{
319 return FALSE;
320}
321//******************************************************************************
322//******************************************************************************
323BOOL Win32LxDll::isLxDll() const
324{
325 return TRUE;
326}
327//******************************************************************************
328//******************************************************************************
329void Win32LxDll::setDllHandleOS2(HINSTANCE hInstanceOS2)
330{
331 //Loaded with LoadLibrary(Ex); no need for a 2nd DosLoadModule
332 //Dlls that are indirectly loaded (i.e. GDI32->KERNEL32 dependancy) need
333 //this additional DosLoadModule (and setDllHandleOS2 isn't called for those)
334 if(this->hinstanceOS2) {
335 DosFreeModule(this->hinstanceOS2);
336 }
337 this->hinstanceOS2 = hInstanceOS2;
338}
339//******************************************************************************
340//******************************************************************************
341Win32LxDll *Win32LxDll::findModuleByOS2Handle(HINSTANCE hinstance)
342{
343 dlllistmutex.enter();
344
345 Win32DllBase *mod = Win32DllBase::getFirst();
346 while (mod != NULL)
347 {
348 if (mod->isLxDll())
349 {
350 Win32LxDll *lxdll = (Win32LxDll *)mod;
351 if (lxdll->hinstanceOS2 == hinstance)
352 {
353 dlllistmutex.leave();
354 return(lxdll);
355 }
356 }
357 mod = mod->getNext();
358 }
359 dlllistmutex.leave();
360 return(NULL);
361}
362//******************************************************************************
363//******************************************************************************
Note: See TracBrowser for help on using the repository browser.