source: trunk/src/kernel32/windlllx.cpp

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

Merge branch gcc-kmk to trunk.

File size: 15.3 KB
RevLine 
[10397]1/* $Id: windlllx.cpp,v 1.29 2004-01-15 10:39:07 sandervl Exp $ */
[956]2
3/*
4 * Win32 LX Dll class (compiled in OS/2 using Odin32 api)
5 *
[3059]6 * Copyright 1999-2000 Sander van Leeuwen (sandervl@xs4all.nl)
[10397]7 * Copyright 2003 Innotek Systemberatung GmbH (sandervl@innotek.de)
[956]8 *
[6015]9 * TODO: Unloading of dlls probably needs to be fixed due to OS/2 bug
[956]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
[6015]21#include <os2wrap.h> //Odin32 OS/2 api wrappers
[3059]22#include <os2newapi.h>
[956]23#include <stdio.h>
24#include <string.h>
25#include <stdlib.h>
[21916]26#ifndef __GNUC__
[956]27#include <iostream.h>
28#include <fstream.h>
[21916]29#endif
[956]30#include <misc.h>
31#include <win32type.h>
[21916]32#include "windllbase.h"
33#include "windlllx.h"
[3059]34#include "winexepe2lx.h"
[3375]35#include "winexepeldr.h"
[956]36#include <odinlx.h>
[5075]37#include <wprocess.h>
[956]38#include "oslibmisc.h"
[9828]39#include <custombuild.h>
[956]40
[3059]41#include <exe386.h>
42
[6015]43#define DBG_LOCALLOG DBG_windlllx
[2802]44#include "dbglocal.h"
45
[9828]46/*******************************************************************************
47* Global Variables *
48*******************************************************************************/
[9411]49char *lpszCustomDllName = NULL;
[10397]50PIMAGE_FILE_HEADER lpCustomDllPEHdr = NULL;
[6401]51
[9828]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
[956]59//******************************************************************************
[6401]60//******************************************************************************
[10397]61void WIN32API SetCustomBuildName(char *lpszName, PIMAGE_FILE_HEADER pfh)
[6401]62{
[9411]63 lpszCustomDllName = lpszName;
[10397]64 lpCustomDllPEHdr = pfh;
[6401]65}
66//******************************************************************************
[956]67//Create LX Dll object and send process attach message
68//System dlls set EntryPoint to 0
[3993]69//Parameters:
[6015]70// HINSTANCE hInstance - OS/2 module handle
[3993]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//
[1423]78//Returns: Odin32 module handle
[956]79//******************************************************************************
[6015]80DWORD WIN32API RegisterLxDll(HINSTANCE hInstance, WIN32DLLENTRY EntryPoint,
81 PVOID pResData,
82 DWORD MajorImageVersion,
[3993]83 DWORD MinorImageVersion,
84 DWORD Subsystem)
[6015]85{
[3993]86 APIRET rc;
87 Win32LxDll *windll;
[3059]88 Win32DllBase *windlldep;
[3993]89 char szFileName[CCHMAXPATH], szErrName[CCHMAXPATH];
[956]90
[6401]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 }
[956]104 }
[10397]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 }
[3993]113 windll = new Win32LxDll(hInstance, EntryPoint, pResData, MajorImageVersion,
114 MinorImageVersion, Subsystem);
[956]115 if(windll == NULL) {
[6401]116 dprintf(("RegisterLxDll: windll == NULL!!!"));
117 return 0;
[956]118 }
[7075]119 //clear name override in case dll init loads another dll
120 lpszCustomDllName = NULL;
[10397]121 lpCustomDllPEHdr = NULL;
[7075]122
[3375]123 if(!fPeLoader) {
[6401]124 windll->AddRef();
[1423]125
[6401]126 if(windll->attachProcess() == 0)
127 return 0;
[3059]128
[6401]129 return windll->getInstanceHandle();
[3059]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) {
[6401]144 goto hdrerror;
[3059]145 }
146 rc = DosQueryHeaderInfo(hInstance, doshdr.e_lfanew, &lxhdr, sizeof(e32_exe), QHINF_READFILE);
147 if(rc) {
[6401]148 goto hdrerror;
[3059]149 }
150 offset = doshdr.e_lfanew + lxhdr.e32_impmod;
151 for(i=0;i<lxhdr.e32_impmodcnt;i++) {
[6401]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;
[3059]169 }
[8462]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
[1423]177 return windll->getInstanceHandle();
[3059]178
179hdrerror:
180 dprintf(("DosQueryHeaderInfo returned %d", rc));
181 return windll->getInstanceHandle();
[956]182}
183//******************************************************************************
184//Destroy LX Dll object
185//******************************************************************************
186BOOL WIN32API UnregisterLxDll(HINSTANCE hInstance)
187{
[3993]188 Win32DllBase *windll;
[956]189
[3059]190 //Don't proceed for pe2lx/win32k (os/2 dll unload dependency bug)
191 //Don't do it either after ExitProcess has been called
[3375]192 if(!fPeLoader || WinExe == NULL)
[6015]193 return TRUE;
[3059]194
[3993]195 windll = Win32DllBase::findModule(hInstance);
[956]196 if(!windll) {
[6015]197 dprintf(("UnregisterLxDll: Can't find dll with handle %x (already deleted)", hInstance));
198 return TRUE; //already deleted by Win32LxDll::Release
[956]199 }
[3059]200 dprintf(("UnregisterLxDll %s", windll->getModuleName()));
201 //This can only happen for LX dependencies (i.e. wininet loads wsock32)
[956]202 delete windll;
203 return TRUE;
204}
205//******************************************************************************
206//******************************************************************************
[3993]207Win32LxDll::Win32LxDll(HINSTANCE hInstance, WIN32DLLENTRY EntryPoint, PVOID pResData,
208 DWORD MajorImageVersion, DWORD MinorImageVersion,
[6015]209 DWORD Subsystem)
[956]210 : Win32ImageBase(hInstance),
[6015]211 Win32LxImage(hInstance, pResData),
[956]212 Win32DllBase(hInstance, EntryPoint)
213{
[5075]214 this->MajorImageVersion = MajorImageVersion;
215 this->MinorImageVersion = MinorImageVersion;
216 this->Subsystem = Subsystem;
[6015]217
[956]218 if(EntryPoint == NULL) {
[6015]219 fSkipThreadEntryCalls = TRUE;
220 fAttachedToProcess = TRUE;
[956]221 }
[3993]222 hinstanceOS2 = hInstance;
223 //new win32 instance handle must be pointer to PE header
224 hinstance = (HINSTANCE)buildHeader(MajorImageVersion, MinorImageVersion,
225 Subsystem);
[4433]226 dprintf(("Fake PE header %x for dll %s", hinstance, getModuleName()));
[956]227}
228//******************************************************************************
229//******************************************************************************
230Win32LxDll::~Win32LxDll()
231{
232}
233//******************************************************************************
[4407]234//Returns reference count or -1 if load failed (PE loader only!)
[956]235//******************************************************************************
[3059]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
[3375]252 if(!fPeLoader)
[6015]253 return ret;
[3059]254
[6015]255 if(referenced == 1)
[3059]256 {
[6015]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 }
[3059]265#ifdef DEBUG
[6015]266 dll->AddRef(getModuleName());
[3059]267#else
[6015]268 dll->AddRef();
[3059]269#endif
[6015]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 }
[3059]276 }
[6015]277 return ret;
[3059]278}
279//******************************************************************************
280//******************************************************************************
[956]281ULONG Win32LxDll::Release()
[6015]282{
[9828]283 HINSTANCE hinst = hinstanceOS2;
284 HINSTANCE hinstOdin = hinstance;
[5075]285 WIN32DLLENTRY EntryPointTmp = dllEntryPoint;
286 PVOID pResDataTmp = (PVOID)pResRootDir;
287 DWORD MajorImageVersionTmp = MajorImageVersion;
288 DWORD MinorImageVersionTmp = MinorImageVersion;
289 DWORD SubsystemTmp = Subsystem;
[9828]290 BOOL fNoUnload = fDisableUnload; //only set for kernel32.dll
291 BOOL fDynLoaded = isDynamicLib();
[5075]292 ULONG ret;
293 APIRET rc;
[956]294
[3059]295 ret = Win32DllBase::Release();
[9828]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)
[6015]319 //DosFreeModule sends a termination message to the dll.
[8459]320 //The LX dll informs us when it's removed (UnregisterDll call)
[6015]321 rc = DosFreeModule(hinst);
322 if(rc) {
[5075]323 dprintf(("Win32LxDll::Release: DosFreeModule %x returned %d", hinst, rc));
[9828]324 if(rc == ERROR_INVALID_ACCESS && !fExitProcess)
[8459]325 {
[9828]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
[5075]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!"));
[6015]336 RegisterLxDll(hinst, EntryPointTmp, pResDataTmp,
337 MajorImageVersionTmp,
[5075]338 MinorImageVersionTmp,
339 SubsystemTmp);
340
341 /* OS/2 dll, system dll, converted dll or win32k took care of it. */
[9828]342 Win32LxDll *pModule = Win32LxDll::findModuleByOS2Handle(hinst);
[5075]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 }
[6015]359 }
[956]360 }
361 return(ret);
362}
363//******************************************************************************
364//******************************************************************************
[6015]365BOOL Win32LxDll::isPe2LxDll() const
[956]366{
[6015]367 return FALSE;
368}
369//******************************************************************************
370//******************************************************************************
371BOOL Win32LxDll::isLxDll() const
372{
[956]373 return TRUE;
374}
375//******************************************************************************
376//******************************************************************************
[6015]377void Win32LxDll::setDllHandleOS2(HINSTANCE hInstanceOS2)
378{
[3993]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) {
[6015]383 DosFreeModule(this->hinstanceOS2);
[3993]384 }
385 this->hinstanceOS2 = hInstanceOS2;
386}
387//******************************************************************************
388//******************************************************************************
389Win32LxDll *Win32LxDll::findModuleByOS2Handle(HINSTANCE hinstance)
390{
[6015]391 dlllistmutex.enter();
[3993]392
[6015]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 }
[3993]404 }
[6015]405 mod = mod->getNext();
406 }
407 dlllistmutex.leave();
408 return(NULL);
[3993]409}
410//******************************************************************************
411//******************************************************************************
[9828]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.