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

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

custom build updates

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