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

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

SetCustomBuildName change for different ordinal base of custom build subdlls

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