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

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

custom build fixes

File size: 12.9 KB
Line 
1/* $Id: windlllx.cpp,v 1.23 2001-10-16 11:39:38 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//******************************************************************************
199//******************************************************************************
200Win32LxDll::~Win32LxDll()
201{
202}
203//******************************************************************************
204//Returns reference count or -1 if load failed (PE loader only!)
205//******************************************************************************
206#ifdef DEBUG
207ULONG Win32LxDll::AddRef(char *parentname)
208#else
209ULONG Win32LxDll::AddRef()
210#endif
211{
212 Win32DllBase *dll;
213 QueueItem *item;
214 ULONG ret;
215
216#ifdef DEBUG
217 ret = Win32DllBase::AddRef(parentname);
218#else
219 ret = Win32DllBase::AddRef();
220#endif
221
222 if(!fPeLoader)
223 return ret;
224
225 if(referenced == 1)
226 {
227 item = loadedDlls.Head();
228 while(item) {
229 dll = (Win32DllBase *)loadedDlls.getItem(item);
230 if(dll == NULL) {
231 dprintf(("ERROR: Win32DllBase::AddRef: dll item == NULL!!"));
232 DebugInt3();
233 return -1;
234 }
235#ifdef DEBUG
236 dll->AddRef(getModuleName());
237#else
238 dll->AddRef();
239#endif
240 item = loadedDlls.getNext(item);
241 }
242 if(attachProcess() == 0) {
243 dprintf(("WARNING: Dll %s refused to be loaded; aborting", getName()));
244 return -1;
245 }
246 }
247 return ret;
248}
249//******************************************************************************
250//******************************************************************************
251ULONG Win32LxDll::Release()
252{
253 HINSTANCE hinst;
254 WIN32DLLENTRY EntryPointTmp = dllEntryPoint;
255 PVOID pResDataTmp = (PVOID)pResRootDir;
256 DWORD MajorImageVersionTmp = MajorImageVersion;
257 DWORD MinorImageVersionTmp = MinorImageVersion;
258 DWORD SubsystemTmp = Subsystem;
259 ULONG ret;
260 APIRET rc;
261 BOOL fNoUnload = fDisableUnload; //only set for kernel32.dll
262 Win32LxDll *pModule;
263
264 hinst = hinstanceOS2;
265 ret = Win32DllBase::Release();
266 if(ret == 0 && !fNoUnload) {//only set for kernel32.dll (fDisableUnload)
267 //DosFreeModule sends a termination message to the dll.
268 //The LX dll informs us when it's removed (UnregisterDll call)
269 rc = DosFreeModule(hinst);
270 if(rc) {
271 dprintf(("Win32LxDll::Release: DosFreeModule %x returned %d", hinst, rc));
272 if(rc == ERROR_INVALID_ACCESS && !fExitProcess) {
273 //Dll refused to unload because it has an active exitlist handler
274 //or depends on a dll that registered an exitlist handler
275 //In this case the handle remains valid and the entrypoint of
276 //the dll is NOT called for DLL_PROCESS_DETACH
277 //WORKAROUND: Re-register the dll so future LoadLibrary calls
278 // don't fail!
279 dprintf(("WORKAROUND: Re-register the dll so future LoadLibrary calls don't fail!"));
280 RegisterLxDll(hinst, EntryPointTmp, pResDataTmp,
281 MajorImageVersionTmp,
282 MinorImageVersionTmp,
283 SubsystemTmp);
284
285 /* OS/2 dll, system dll, converted dll or win32k took care of it. */
286 pModule = Win32LxDll::findModuleByOS2Handle(hinst);
287 if(pModule)
288 {
289 pModule->setDllHandleOS2(hinst);
290 if(fPeLoader)
291 {
292 if(pModule->AddRef() == -1) {//-1 -> load failed (attachProcess)
293 dprintf(("ERROR Dll refused to be loaded; aborting"));
294 DebugInt3();
295 delete pModule;
296 return 0;
297 }
298 }
299 pModule->incDynamicLib();
300 }
301 else DebugInt3();
302 }
303 }
304 }
305 return(ret);
306}
307//******************************************************************************
308//******************************************************************************
309BOOL Win32LxDll::isPe2LxDll() const
310{
311 return FALSE;
312}
313//******************************************************************************
314//******************************************************************************
315BOOL Win32LxDll::isLxDll() const
316{
317 return TRUE;
318}
319//******************************************************************************
320//******************************************************************************
321void Win32LxDll::setDllHandleOS2(HINSTANCE hInstanceOS2)
322{
323 //Loaded with LoadLibrary(Ex); no need for a 2nd DosLoadModule
324 //Dlls that are indirectly loaded (i.e. GDI32->KERNEL32 dependancy) need
325 //this additional DosLoadModule (and setDllHandleOS2 isn't called for those)
326 if(this->hinstanceOS2) {
327 DosFreeModule(this->hinstanceOS2);
328 }
329 this->hinstanceOS2 = hInstanceOS2;
330}
331//******************************************************************************
332//******************************************************************************
333Win32LxDll *Win32LxDll::findModuleByOS2Handle(HINSTANCE hinstance)
334{
335 dlllistmutex.enter();
336
337 Win32DllBase *mod = Win32DllBase::getFirst();
338 while (mod != NULL)
339 {
340 if (mod->isLxDll())
341 {
342 Win32LxDll *lxdll = (Win32LxDll *)mod;
343 if (lxdll->hinstanceOS2 == hinstance)
344 {
345 dlllistmutex.leave();
346 return(lxdll);
347 }
348 }
349 mod = mod->getNext();
350 }
351 dlllistmutex.leave();
352 return(NULL);
353}
354//******************************************************************************
355//******************************************************************************
Note: See TracBrowser for help on using the repository browser.