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

Last change on this file since 21916 was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

File size: 15.3 KB
Line 
1/* $Id: windlllx.cpp,v 1.29 2004-01-15 10:39:07 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 * Copyright 2003 Innotek Systemberatung GmbH (sandervl@innotek.de)
8 *
9 * TODO: Unloading of dlls probably needs to be fixed due to OS/2 bug
10 * (wrong unload order of dlls)
11 *
12 * Project Odin Software License can be found in LICENSE.TXT
13 *
14 */
15#define INCL_DOSFILEMGR /* File Manager values */
16#define INCL_DOSERRORS /* DOS Error values */
17#define INCL_DOSPROCESS /* DOS Process values */
18#define INCL_DOSMODULEMGR
19#define INCL_DOSMISC /* DOS Miscellanous values */
20#define INCL_WIN
21#include <os2wrap.h> //Odin32 OS/2 api wrappers
22#include <os2newapi.h>
23#include <stdio.h>
24#include <string.h>
25#include <stdlib.h>
26#ifndef __GNUC__
27#include <iostream.h>
28#include <fstream.h>
29#endif
30#include <misc.h>
31#include <win32type.h>
32#include "windllbase.h"
33#include "windlllx.h"
34#include "winexepe2lx.h"
35#include "winexepeldr.h"
36#include <odinlx.h>
37#include <wprocess.h>
38#include "oslibmisc.h"
39#include <custombuild.h>
40
41#include <exe386.h>
42
43#define DBG_LOCALLOG DBG_windlllx
44#include "dbglocal.h"
45
46/*******************************************************************************
47* Global Variables *
48*******************************************************************************/
49char *lpszCustomDllName = NULL;
50PIMAGE_FILE_HEADER lpCustomDllPEHdr = NULL;
51
52/**
53 * FreeLibrary callback for LX Dlls, it's call only when the library is actually
54 * being unloaded.
55 * Maintained by ODIN_SetLxDllUnLoadCallback().
56 */
57PFNLXDLLUNLOAD pfnLxDllUnLoadCallback = NULL;
58
59//******************************************************************************
60//******************************************************************************
61void WIN32API SetCustomBuildName(char *lpszName, PIMAGE_FILE_HEADER pfh)
62{
63 lpszCustomDllName = lpszName;
64 lpCustomDllPEHdr = pfh;
65}
66//******************************************************************************
67//Create LX Dll object and send process attach message
68//System dlls set EntryPoint to 0
69//Parameters:
70// HINSTANCE hInstance - OS/2 module handle
71// WIN32DLLENTRY EntryPoint - Win32 dll entrypoint address
72// PVOID pResData - pointer to win32 resource data
73// DWORD MajorImageVersion - major image/os version (for fake win32 header)
74// DWORD MinorImageVersion - minor image/os version (for fake win32 header)
75// DWORD Subsystem - subsystem type (for fake win32 header)
76// (IMAGE_SUBSYSTEM_WINDOWS_CUI/IMAGE_SUBSYSTEM_WINDOWS_GUI)
77//
78//Returns: Odin32 module handle
79//******************************************************************************
80DWORD WIN32API RegisterLxDll(HINSTANCE hInstance, WIN32DLLENTRY EntryPoint,
81 PVOID pResData,
82 DWORD MajorImageVersion,
83 DWORD MinorImageVersion,
84 DWORD Subsystem)
85{
86 APIRET rc;
87 Win32LxDll *windll;
88 Win32DllBase *windlldep;
89 char szFileName[CCHMAXPATH], szErrName[CCHMAXPATH];
90
91 if(!lpszCustomDllName) {
92 if(OSLibGetDllName(hInstance, szFileName, sizeof(szFileName)) == FALSE) {
93 dprintf(("ERROR: RegisterLxDll: OSLibGetDllName %x failed!!", hInstance));
94 return 0;
95 }
96 dprintf(("RegisterLxDll %x %s", hInstance, szFileName));
97 //Make sure DosLoadModule is called at least once for a dll (to make sure
98 //OS/2 doesn't unload the dll when it's still needed)
99 rc = DosLoadModule(szErrName, sizeof(szErrName), szFileName, &hInstance);
100 if(rc != 0) {
101 dprintf(("ERROR: RegisterLxDll: DosLoadModule %s failed (rc=%d)!!", szFileName, rc));
102 return 0;
103 }
104 }
105 else {
106 //make sure this dll hasn't already been loaded
107 if(Win32DllBase::findModule(lpszCustomDllName) != NULL) {
108 dprintf(("ERROR: RegisterLxDll: module %s already loaded!!", lpszCustomDllName));
109 DebugInt3();
110 return 0;
111 }
112 }
113 windll = new Win32LxDll(hInstance, EntryPoint, pResData, MajorImageVersion,
114 MinorImageVersion, Subsystem);
115 if(windll == NULL) {
116 dprintf(("RegisterLxDll: windll == NULL!!!"));
117 return 0;
118 }
119 //clear name override in case dll init loads another dll
120 lpszCustomDllName = NULL;
121 lpCustomDllPEHdr = NULL;
122
123 if(!fPeLoader) {
124 windll->AddRef();
125
126 if(windll->attachProcess() == 0)
127 return 0;
128
129 return windll->getInstanceHandle();
130 }
131 IMAGE_DOS_HEADER doshdr;
132 struct e32_exe lxhdr;
133 ULONG offset;
134 char modulename[CCHMAXPATH];
135 char modsize;
136 int i;
137
138 //SvL: This code reads the import name table of the dll to get the dependencies
139 // on other dlls.
140 //DosQueryHeaderInfo is an undocumented api, but works very well.
141 //(no need to save FS here as we'll return to OS/2 immediately)
142 rc = DosQueryHeaderInfo(hInstance, 0, &doshdr, sizeof(IMAGE_DOS_HEADER), QHINF_READFILE);
143 if(rc) {
144 goto hdrerror;
145 }
146 rc = DosQueryHeaderInfo(hInstance, doshdr.e_lfanew, &lxhdr, sizeof(e32_exe), QHINF_READFILE);
147 if(rc) {
148 goto hdrerror;
149 }
150 offset = doshdr.e_lfanew + lxhdr.e32_impmod;
151 for(i=0;i<lxhdr.e32_impmodcnt;i++) {
152 rc = DosQueryHeaderInfo(hInstance, offset, &modsize, 1, QHINF_READFILE);
153 if(rc) {
154 goto hdrerror;
155 }
156 rc = DosQueryHeaderInfo(hInstance, offset+1, &modulename, min(modsize, sizeof(modulename)), QHINF_READFILE);
157 if(rc) {
158 goto hdrerror;
159 }
160 modulename[modsize] = 0;
161 windlldep = Win32DllBase::findModule(modulename, TRUE);
162 if(windlldep && strcmp(windlldep->getModuleName(), windll->getModuleName())) {
163 dprintf(("RegisterLxDll: Add dependency %s -> %s", windll->getModuleName(), modulename));
164 windll->addDependency(windlldep);
165 }
166 else dprintf(("HARMLESS WARNING: Can't find dll %s referenced by %s", modulename, windll->getModuleName()));
167
168 offset += modsize + 1;
169 }
170#ifdef HACK_NEVER_UNLOAD_LX_DLLS
171 //HACK ALERT!!
172 //This makes sure the LX dll never gets unloaded.
173 //Necessary since unloading doesn't work due to dependencies on dlls
174 //with exitlist handlers.
175 windll->AddRef();
176#endif
177 return windll->getInstanceHandle();
178
179hdrerror:
180 dprintf(("DosQueryHeaderInfo returned %d", rc));
181 return windll->getInstanceHandle();
182}
183//******************************************************************************
184//Destroy LX Dll object
185//******************************************************************************
186BOOL WIN32API UnregisterLxDll(HINSTANCE hInstance)
187{
188 Win32DllBase *windll;
189
190 //Don't proceed for pe2lx/win32k (os/2 dll unload dependency bug)
191 //Don't do it either after ExitProcess has been called
192 if(!fPeLoader || WinExe == NULL)
193 return TRUE;
194
195 windll = Win32DllBase::findModule(hInstance);
196 if(!windll) {
197 dprintf(("UnregisterLxDll: Can't find dll with handle %x (already deleted)", hInstance));
198 return TRUE; //already deleted by Win32LxDll::Release
199 }
200 dprintf(("UnregisterLxDll %s", windll->getModuleName()));
201 //This can only happen for LX dependencies (i.e. wininet loads wsock32)
202 delete windll;
203 return TRUE;
204}
205//******************************************************************************
206//******************************************************************************
207Win32LxDll::Win32LxDll(HINSTANCE hInstance, WIN32DLLENTRY EntryPoint, PVOID pResData,
208 DWORD MajorImageVersion, DWORD MinorImageVersion,
209 DWORD Subsystem)
210 : Win32ImageBase(hInstance),
211 Win32LxImage(hInstance, pResData),
212 Win32DllBase(hInstance, EntryPoint)
213{
214 this->MajorImageVersion = MajorImageVersion;
215 this->MinorImageVersion = MinorImageVersion;
216 this->Subsystem = Subsystem;
217
218 if(EntryPoint == NULL) {
219 fSkipThreadEntryCalls = TRUE;
220 fAttachedToProcess = TRUE;
221 }
222 hinstanceOS2 = hInstance;
223 //new win32 instance handle must be pointer to PE header
224 hinstance = (HINSTANCE)buildHeader(MajorImageVersion, MinorImageVersion,
225 Subsystem);
226 dprintf(("Fake PE header %x for dll %s", hinstance, getModuleName()));
227}
228//******************************************************************************
229//******************************************************************************
230Win32LxDll::~Win32LxDll()
231{
232}
233//******************************************************************************
234//Returns reference count or -1 if load failed (PE loader only!)
235//******************************************************************************
236#ifdef DEBUG
237ULONG Win32LxDll::AddRef(char *parentname)
238#else
239ULONG Win32LxDll::AddRef()
240#endif
241{
242 Win32DllBase *dll;
243 QueueItem *item;
244 ULONG ret;
245
246#ifdef DEBUG
247 ret = Win32DllBase::AddRef(parentname);
248#else
249 ret = Win32DllBase::AddRef();
250#endif
251
252 if(!fPeLoader)
253 return ret;
254
255 if(referenced == 1)
256 {
257 item = loadedDlls.Head();
258 while(item) {
259 dll = (Win32DllBase *)loadedDlls.getItem(item);
260 if(dll == NULL) {
261 dprintf(("ERROR: Win32DllBase::AddRef: dll item == NULL!!"));
262 DebugInt3();
263 return -1;
264 }
265#ifdef DEBUG
266 dll->AddRef(getModuleName());
267#else
268 dll->AddRef();
269#endif
270 item = loadedDlls.getNext(item);
271 }
272 if(attachProcess() == 0) {
273 dprintf(("WARNING: Dll %s refused to be loaded; aborting", getName()));
274 return -1;
275 }
276 }
277 return ret;
278}
279//******************************************************************************
280//******************************************************************************
281ULONG Win32LxDll::Release()
282{
283 HINSTANCE hinst = hinstanceOS2;
284 HINSTANCE hinstOdin = hinstance;
285 WIN32DLLENTRY EntryPointTmp = dllEntryPoint;
286 PVOID pResDataTmp = (PVOID)pResRootDir;
287 DWORD MajorImageVersionTmp = MajorImageVersion;
288 DWORD MinorImageVersionTmp = MinorImageVersion;
289 DWORD SubsystemTmp = Subsystem;
290 BOOL fNoUnload = fDisableUnload; //only set for kernel32.dll
291 BOOL fDynLoaded = isDynamicLib();
292 ULONG ret;
293 APIRET rc;
294
295 ret = Win32DllBase::Release();
296
297 /** @sketch
298 * If this module is not unreference and it was loaded using LoadLibrary() then
299 * call the custombuild callback if present.
300 * The callback should call UnRegisterLxDll().
301 * Endif
302 *
303 * @remark
304 * #ifdef HACK_NEVER_UNLOAD_LX_DLLS
305 * This will never be called!
306 * #endif
307 *
308 * @todo: call pfnLxDllLoadCallback if DosFreeModule failes.
309 * It's not implemented because it's complex and at the moment we will
310 * never actually get here.
311 * So, this callback is here just as a reminder eventhough it's working..
312 */
313 if (!ret && fDynLoaded && pfnLxDllUnLoadCallback)
314 {
315 pfnLxDllUnLoadCallback(hinstanceOS2, hinstance);
316 }
317
318 if (ret == 0 && !fNoUnload) {//only set for kernel32.dll (fDisableUnload)
319 //DosFreeModule sends a termination message to the dll.
320 //The LX dll informs us when it's removed (UnregisterDll call)
321 rc = DosFreeModule(hinst);
322 if(rc) {
323 dprintf(("Win32LxDll::Release: DosFreeModule %x returned %d", hinst, rc));
324 if(rc == ERROR_INVALID_ACCESS && !fExitProcess)
325 {
326 #ifndef HACK_NEVER_UNLOAD_LX_DLLS
327 #error @todo: call pfnLxDllLoadCallback and let it do the registering if it did that on the initial load..
328 #endif
329 //Dll refused to unload because it has an active exitlist handler
330 //or depends on a dll that registered an exitlist handler
331 //In this case the handle remains valid and the entrypoint of
332 //the dll is NOT called for DLL_PROCESS_DETACH
333 //WORKAROUND: Re-register the dll so future LoadLibrary calls
334 // don't fail!
335 dprintf(("WORKAROUND: Re-register the dll so future LoadLibrary calls don't fail!"));
336 RegisterLxDll(hinst, EntryPointTmp, pResDataTmp,
337 MajorImageVersionTmp,
338 MinorImageVersionTmp,
339 SubsystemTmp);
340
341 /* OS/2 dll, system dll, converted dll or win32k took care of it. */
342 Win32LxDll *pModule = Win32LxDll::findModuleByOS2Handle(hinst);
343 if(pModule)
344 {
345 pModule->setDllHandleOS2(hinst);
346 if(fPeLoader)
347 {
348 if(pModule->AddRef() == -1) {//-1 -> load failed (attachProcess)
349 dprintf(("ERROR Dll refused to be loaded; aborting"));
350 DebugInt3();
351 delete pModule;
352 return 0;
353 }
354 }
355 pModule->incDynamicLib();
356 }
357 else DebugInt3();
358 }
359 }
360 }
361 return(ret);
362}
363//******************************************************************************
364//******************************************************************************
365BOOL Win32LxDll::isPe2LxDll() const
366{
367 return FALSE;
368}
369//******************************************************************************
370//******************************************************************************
371BOOL Win32LxDll::isLxDll() const
372{
373 return TRUE;
374}
375//******************************************************************************
376//******************************************************************************
377void Win32LxDll::setDllHandleOS2(HINSTANCE hInstanceOS2)
378{
379 //Loaded with LoadLibrary(Ex); no need for a 2nd DosLoadModule
380 //Dlls that are indirectly loaded (i.e. GDI32->KERNEL32 dependancy) need
381 //this additional DosLoadModule (and setDllHandleOS2 isn't called for those)
382 if(this->hinstanceOS2) {
383 DosFreeModule(this->hinstanceOS2);
384 }
385 this->hinstanceOS2 = hInstanceOS2;
386}
387//******************************************************************************
388//******************************************************************************
389Win32LxDll *Win32LxDll::findModuleByOS2Handle(HINSTANCE hinstance)
390{
391 dlllistmutex.enter();
392
393 Win32DllBase *mod = Win32DllBase::getFirst();
394 while (mod != NULL)
395 {
396 if (mod->isLxDll())
397 {
398 Win32LxDll *lxdll = (Win32LxDll *)mod;
399 if (lxdll->hinstanceOS2 == hinstance)
400 {
401 dlllistmutex.leave();
402 return(lxdll);
403 }
404 }
405 mod = mod->getNext();
406 }
407 dlllistmutex.leave();
408 return(NULL);
409}
410//******************************************************************************
411//******************************************************************************
412
413/**
414 * Custombuild API for registering a callback for LX Dll loading thru LoadLibrary*().
415 * @returns Success indicator.
416 * @param pfn Pointer to callback.
417 * NULL if callback is deregistered.
418 */
419BOOL WIN32API ODIN_SetLxDllUnLoadCallback(PFNLXDLLUNLOAD pfn)
420{
421 pfnLxDllUnLoadCallback = pfn;
422 return TRUE;
423}
424
Note: See TracBrowser for help on using the repository browser.