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

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

Added support for renaming of exported functions

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