| 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 |  | 
|---|
| 42 | char *lpszCustomDllName = NULL; | 
|---|
| 43 | ULONG dwOrdinalBase = 0; | 
|---|
| 44 |  | 
|---|
| 45 | //****************************************************************************** | 
|---|
| 46 | //****************************************************************************** | 
|---|
| 47 | void 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 | //****************************************************************************** | 
|---|
| 66 | DWORD 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 |  | 
|---|
| 149 | hdrerror: | 
|---|
| 150 | dprintf(("DosQueryHeaderInfo returned %d", rc)); | 
|---|
| 151 | return windll->getInstanceHandle(); | 
|---|
| 152 | } | 
|---|
| 153 | //****************************************************************************** | 
|---|
| 154 | //Destroy LX Dll object | 
|---|
| 155 | //****************************************************************************** | 
|---|
| 156 | BOOL 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 | //****************************************************************************** | 
|---|
| 177 | Win32LxDll::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 | //****************************************************************************** | 
|---|
| 200 | Win32LxDll::~Win32LxDll() | 
|---|
| 201 | { | 
|---|
| 202 | } | 
|---|
| 203 | //****************************************************************************** | 
|---|
| 204 | //Returns reference count or -1 if load failed (PE loader only!) | 
|---|
| 205 | //****************************************************************************** | 
|---|
| 206 | #ifdef DEBUG | 
|---|
| 207 | ULONG Win32LxDll::AddRef(char *parentname) | 
|---|
| 208 | #else | 
|---|
| 209 | ULONG 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 | //****************************************************************************** | 
|---|
| 251 | ULONG 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 | //****************************************************************************** | 
|---|
| 309 | BOOL Win32LxDll::isPe2LxDll() const | 
|---|
| 310 | { | 
|---|
| 311 | return FALSE; | 
|---|
| 312 | } | 
|---|
| 313 | //****************************************************************************** | 
|---|
| 314 | //****************************************************************************** | 
|---|
| 315 | BOOL Win32LxDll::isLxDll() const | 
|---|
| 316 | { | 
|---|
| 317 | return TRUE; | 
|---|
| 318 | } | 
|---|
| 319 | //****************************************************************************** | 
|---|
| 320 | //****************************************************************************** | 
|---|
| 321 | void 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 | //****************************************************************************** | 
|---|
| 333 | Win32LxDll *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 | //****************************************************************************** | 
|---|