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

Last change on this file since 5782 was 5782, checked in by sandervl, 24 years ago

Check name before adding dependency for module

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