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

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

Make sure LX dlls can never be unloaded

File size: 13.1 KB
Line 
1/* $Id: windlllx.cpp,v 1.24 2002-05-20 14:22:37 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 return windll->getInstanceHandle();
148
149hdrerror:
150 dprintf(("DosQueryHeaderInfo returned %d", rc));
151 return windll->getInstanceHandle();
152}
153//******************************************************************************
154//Destroy LX Dll object
155//******************************************************************************
156BOOL WIN32API UnregisterLxDll(HINSTANCE hInstance)
157{
158 Win32DllBase *windll;
159
160 //Don't proceed for pe2lx/win32k (os/2 dll unload dependency bug)
161 //Don't do it either after ExitProcess has been called
162 if(!fPeLoader || WinExe == NULL)
163 return TRUE;
164
165 windll = Win32DllBase::findModule(hInstance);
166 if(!windll) {
167 dprintf(("UnregisterLxDll: Can't find dll with handle %x (already deleted)", hInstance));
168 return TRUE; //already deleted by Win32LxDll::Release
169 }
170 dprintf(("UnregisterLxDll %s", windll->getModuleName()));
171 //This can only happen for LX dependencies (i.e. wininet loads wsock32)
172 delete windll;
173 return TRUE;
174}
175//******************************************************************************
176//******************************************************************************
177Win32LxDll::Win32LxDll(HINSTANCE hInstance, WIN32DLLENTRY EntryPoint, PVOID pResData,
178 DWORD MajorImageVersion, DWORD MinorImageVersion,
179 DWORD Subsystem)
180 : Win32ImageBase(hInstance),
181 Win32LxImage(hInstance, pResData),
182 Win32DllBase(hInstance, EntryPoint)
183{
184 this->MajorImageVersion = MajorImageVersion;
185 this->MinorImageVersion = MinorImageVersion;
186 this->Subsystem = Subsystem;
187
188 if(EntryPoint == NULL) {
189 fSkipThreadEntryCalls = TRUE;
190 fAttachedToProcess = TRUE;
191 }
192 hinstanceOS2 = hInstance;
193 //new win32 instance handle must be pointer to PE header
194 hinstance = (HINSTANCE)buildHeader(MajorImageVersion, MinorImageVersion,
195 Subsystem);
196 dprintf(("Fake PE header %x for dll %s", hinstance, getModuleName()));
197
198 //HACK ALERT!!
199 //This makes sure the LX dll never gets unloaded.
200 //Necessary since unloading doesn't work due to dependencies on dlls
201 //with exitlist handlers.
202 referenced++;
203}
204//******************************************************************************
205//******************************************************************************
206Win32LxDll::~Win32LxDll()
207{
208}
209//******************************************************************************
210//Returns reference count or -1 if load failed (PE loader only!)
211//******************************************************************************
212#ifdef DEBUG
213ULONG Win32LxDll::AddRef(char *parentname)
214#else
215ULONG Win32LxDll::AddRef()
216#endif
217{
218 Win32DllBase *dll;
219 QueueItem *item;
220 ULONG ret;
221
222#ifdef DEBUG
223 ret = Win32DllBase::AddRef(parentname);
224#else
225 ret = Win32DllBase::AddRef();
226#endif
227
228 if(!fPeLoader)
229 return ret;
230
231 if(referenced == 1)
232 {
233 item = loadedDlls.Head();
234 while(item) {
235 dll = (Win32DllBase *)loadedDlls.getItem(item);
236 if(dll == NULL) {
237 dprintf(("ERROR: Win32DllBase::AddRef: dll item == NULL!!"));
238 DebugInt3();
239 return -1;
240 }
241#ifdef DEBUG
242 dll->AddRef(getModuleName());
243#else
244 dll->AddRef();
245#endif
246 item = loadedDlls.getNext(item);
247 }
248 if(attachProcess() == 0) {
249 dprintf(("WARNING: Dll %s refused to be loaded; aborting", getName()));
250 return -1;
251 }
252 }
253 return ret;
254}
255//******************************************************************************
256//******************************************************************************
257ULONG Win32LxDll::Release()
258{
259 HINSTANCE hinst;
260 WIN32DLLENTRY EntryPointTmp = dllEntryPoint;
261 PVOID pResDataTmp = (PVOID)pResRootDir;
262 DWORD MajorImageVersionTmp = MajorImageVersion;
263 DWORD MinorImageVersionTmp = MinorImageVersion;
264 DWORD SubsystemTmp = Subsystem;
265 ULONG ret;
266 APIRET rc;
267 BOOL fNoUnload = fDisableUnload; //only set for kernel32.dll
268 Win32LxDll *pModule;
269
270 hinst = hinstanceOS2;
271 ret = Win32DllBase::Release();
272 if(ret == 0 && !fNoUnload) {//only set for kernel32.dll (fDisableUnload)
273 //DosFreeModule sends a termination message to the dll.
274 //The LX dll informs us when it's removed (UnregisterDll call)
275 rc = DosFreeModule(hinst);
276 if(rc) {
277 dprintf(("Win32LxDll::Release: DosFreeModule %x returned %d", hinst, rc));
278 if(rc == ERROR_INVALID_ACCESS && !fExitProcess)
279 {
280 //Dll refused to unload because it has an active exitlist handler
281 //or depends on a dll that registered an exitlist handler
282 //In this case the handle remains valid and the entrypoint of
283 //the dll is NOT called for DLL_PROCESS_DETACH
284 //WORKAROUND: Re-register the dll so future LoadLibrary calls
285 // don't fail!
286 dprintf(("WORKAROUND: Re-register the dll so future LoadLibrary calls don't fail!"));
287 RegisterLxDll(hinst, EntryPointTmp, pResDataTmp,
288 MajorImageVersionTmp,
289 MinorImageVersionTmp,
290 SubsystemTmp);
291
292 /* OS/2 dll, system dll, converted dll or win32k took care of it. */
293 pModule = Win32LxDll::findModuleByOS2Handle(hinst);
294 if(pModule)
295 {
296 pModule->setDllHandleOS2(hinst);
297 if(fPeLoader)
298 {
299 if(pModule->AddRef() == -1) {//-1 -> load failed (attachProcess)
300 dprintf(("ERROR Dll refused to be loaded; aborting"));
301 DebugInt3();
302 delete pModule;
303 return 0;
304 }
305 }
306 pModule->incDynamicLib();
307 }
308 else DebugInt3();
309 }
310 }
311 }
312 return(ret);
313}
314//******************************************************************************
315//******************************************************************************
316BOOL Win32LxDll::isPe2LxDll() const
317{
318 return FALSE;
319}
320//******************************************************************************
321//******************************************************************************
322BOOL Win32LxDll::isLxDll() const
323{
324 return TRUE;
325}
326//******************************************************************************
327//******************************************************************************
328void Win32LxDll::setDllHandleOS2(HINSTANCE hInstanceOS2)
329{
330 //Loaded with LoadLibrary(Ex); no need for a 2nd DosLoadModule
331 //Dlls that are indirectly loaded (i.e. GDI32->KERNEL32 dependancy) need
332 //this additional DosLoadModule (and setDllHandleOS2 isn't called for those)
333 if(this->hinstanceOS2) {
334 DosFreeModule(this->hinstanceOS2);
335 }
336 this->hinstanceOS2 = hInstanceOS2;
337}
338//******************************************************************************
339//******************************************************************************
340Win32LxDll *Win32LxDll::findModuleByOS2Handle(HINSTANCE hinstance)
341{
342 dlllistmutex.enter();
343
344 Win32DllBase *mod = Win32DllBase::getFirst();
345 while (mod != NULL)
346 {
347 if (mod->isLxDll())
348 {
349 Win32LxDll *lxdll = (Win32LxDll *)mod;
350 if (lxdll->hinstanceOS2 == hinstance)
351 {
352 dlllistmutex.leave();
353 return(lxdll);
354 }
355 }
356 mod = mod->getNext();
357 }
358 dlllistmutex.leave();
359 return(NULL);
360}
361//******************************************************************************
362//******************************************************************************
Note: See TracBrowser for help on using the repository browser.