|  | /** | 
|  | * This file has no copyright assigned and is placed in the Public Domain. | 
|  | * This file is part of the w64 mingw-runtime package. | 
|  | * No warranty is given; refer to the file DISCLAIMER within this package. | 
|  | */ | 
|  | #define WIN32_LEAN_AND_MEAN | 
|  | #include <windows.h> | 
|  |  | 
|  | #include "DelayImp.h" | 
|  |  | 
|  | static inline size_t __strlen(const char *sz) { | 
|  | const char *szEnd = sz; | 
|  | while(*szEnd++) | 
|  | ; | 
|  | return szEnd - sz - 1; | 
|  | } | 
|  |  | 
|  | static inline int __memcmp(const void *pv1,const void *pv2,size_t cb) { | 
|  | if(!cb) return 0; | 
|  | while(--cb && *(char *)pv1==*(char *)pv2) { | 
|  | pv1 = (char *)pv1 + 1; | 
|  | pv2 = (char *)pv2 + 1; | 
|  | } | 
|  | return *((unsigned char *)pv1) - *((unsigned char *)pv2); | 
|  | } | 
|  |  | 
|  | static inline void *__memcpy(void *pvDst,const void *pvSrc,size_t cb) { | 
|  | void *pvRet = pvDst; | 
|  | while(cb--) { | 
|  | *(char *)pvDst = *(char *)pvSrc; | 
|  | pvDst = (char *)pvDst + 1; | 
|  | pvSrc = (char *)pvSrc + 1; | 
|  | } | 
|  | return pvRet; | 
|  | } | 
|  |  | 
|  | inline unsigned IndexFromPImgThunkData(PCImgThunkData pitdCur,PCImgThunkData pitdBase) { return (unsigned) (pitdCur - pitdBase);} | 
|  |  | 
|  | extern "C" | 
|  | const IMAGE_DOS_HEADER __ImageBase; | 
|  |  | 
|  | template <class X> | 
|  | X PFromRva(RVA rva) { return X(PBYTE(&__ImageBase) + rva);} | 
|  |  | 
|  | typedef struct UnloadInfo *PUnloadInfo; | 
|  | typedef struct UnloadInfo { | 
|  | PUnloadInfo puiNext; | 
|  | PCImgDelayDescr pidd; | 
|  | } UnloadInfo; | 
|  |  | 
|  | inline unsigned CountOfImports(PCImgThunkData pitdBase) { | 
|  | unsigned cRet = 0; | 
|  | PCImgThunkData pitd = pitdBase; | 
|  | while(pitd->u1.Function) { | 
|  | pitd++; | 
|  | cRet++; | 
|  | } | 
|  | return cRet; | 
|  | } | 
|  |  | 
|  | extern "C" | 
|  | PUnloadInfo __puiHead = 0; | 
|  |  | 
|  | struct ULI : public UnloadInfo { | 
|  | ULI(PCImgDelayDescr pidd_) { | 
|  | pidd = pidd_; | 
|  | Link(); | 
|  | } | 
|  | ~ULI() { | 
|  | Unlink(); | 
|  | } | 
|  | void *operator new(size_t cb) { return ::LocalAlloc(LPTR,cb);} | 
|  | void operator delete(void *pv) { ::LocalFree(pv);} | 
|  | void Unlink() { | 
|  | PUnloadInfo *ppui = &__puiHead; | 
|  | while(*ppui && *ppui!=this) { | 
|  | ppui = &((*ppui)->puiNext); | 
|  | } | 
|  | if(*ppui==this) *ppui = puiNext; | 
|  | } | 
|  | void Link() { | 
|  | puiNext = __puiHead; | 
|  | __puiHead = this; | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct InternalImgDelayDescr { | 
|  | DWORD grAttrs; | 
|  | LPCSTR szName; | 
|  | HMODULE *phmod; | 
|  | PImgThunkData pIAT; | 
|  | PCImgThunkData pINT; | 
|  | PCImgThunkData pBoundIAT; | 
|  | PCImgThunkData pUnloadIAT; | 
|  | DWORD dwTimeStamp; | 
|  | }; | 
|  |  | 
|  | typedef InternalImgDelayDescr *PIIDD; | 
|  | typedef const InternalImgDelayDescr *PCIIDD; | 
|  |  | 
|  | static inline PIMAGE_NT_HEADERS WINAPI PinhFromImageBase(HMODULE hmod) { return PIMAGE_NT_HEADERS(PBYTE(hmod) + PIMAGE_DOS_HEADER(hmod)->e_lfanew);} | 
|  | static inline void WINAPI OverlayIAT(PImgThunkData pitdDst,PCImgThunkData pitdSrc) { __memcpy(pitdDst,pitdSrc,CountOfImports(pitdDst) *sizeof IMAGE_THUNK_DATA);} | 
|  | static inline DWORD WINAPI TimeStampOfImage(PIMAGE_NT_HEADERS pinh) { return pinh->FileHeader.TimeDateStamp;} | 
|  | static inline bool WINAPI FLoadedAtPreferredAddress(PIMAGE_NT_HEADERS pinh,HMODULE hmod) { return UINT_PTR(hmod)==pinh->OptionalHeader.ImageBase;} | 
|  |  | 
|  | #if(defined(_X86_) && !defined(__x86_64)) | 
|  | #undef InterlockedExchangePointer | 
|  | #define InterlockedExchangePointer(Target,Value) (PVOID)(LONG_PTR)InterlockedExchange((PLONG)(Target),(LONG)(LONG_PTR)(Value)) | 
|  | typedef unsigned long *PULONG_PTR; | 
|  | #endif | 
|  |  | 
|  | extern "C" | 
|  | FARPROC WINAPI __delayLoadHelper2(PCImgDelayDescr pidd,FARPROC *ppfnIATEntry) { | 
|  | InternalImgDelayDescr idd = { | 
|  | pidd->grAttrs,PFromRva<LPCSTR>(pidd->rvaDLLName),PFromRva<HMODULE*>(pidd->rvaHmod),PFromRva<PImgThunkData>(pidd->rvaIAT),PFromRva<PCImgThunkData>(pidd->rvaINT),PFromRva<PCImgThunkData>(pidd->rvaBoundIAT),PFromRva<PCImgThunkData>(pidd->rvaUnloadIAT),pidd->dwTimeStamp | 
|  | }; | 
|  | DelayLoadInfo dli = { | 
|  | sizeof DelayLoadInfo,pidd,ppfnIATEntry,idd.szName,{ 0},0,0,0 | 
|  | }; | 
|  |  | 
|  | if(0==(idd.grAttrs & dlattrRva)) { | 
|  | PDelayLoadInfo rgpdli[1] = { &dli}; | 
|  | RaiseException(VcppException(ERROR_SEVERITY_ERROR,ERROR_INVALID_PARAMETER),0,1,PULONG_PTR(rgpdli)); | 
|  | return 0; | 
|  | } | 
|  | HMODULE hmod = *idd.phmod; | 
|  | const unsigned iIAT = IndexFromPImgThunkData(PCImgThunkData(ppfnIATEntry),idd.pIAT); | 
|  | const unsigned iINT = iIAT; | 
|  | PCImgThunkData pitd = &(idd.pINT[iINT]); | 
|  |  | 
|  | dli.dlp.fImportByName = !IMAGE_SNAP_BY_ORDINAL(pitd->u1.Ordinal); | 
|  | if(dli.dlp.fImportByName) dli.dlp.szProcName = LPCSTR(PFromRva<PIMAGE_IMPORT_BY_NAME>(RVA(UINT_PTR(pitd->u1.AddressOfData)))->Name); | 
|  | else dli.dlp.dwOrdinal = DWORD(IMAGE_ORDINAL(pitd->u1.Ordinal)); | 
|  | FARPROC pfnRet = NULL; | 
|  | if(__pfnDliNotifyHook2) { | 
|  | pfnRet = ((*__pfnDliNotifyHook2)(dliStartProcessing,&dli)); | 
|  | if(pfnRet!=NULL) goto HookBypass; | 
|  | } | 
|  | if(hmod==0) { | 
|  | if(__pfnDliNotifyHook2) hmod = HMODULE(((*__pfnDliNotifyHook2)(dliNotePreLoadLibrary,&dli))); | 
|  | if(hmod==0) hmod = ::LoadLibrary(dli.szDll); | 
|  | if(hmod==0) { | 
|  | dli.dwLastError = ::GetLastError(); | 
|  | if(__pfnDliFailureHook2) hmod = HMODULE((*__pfnDliFailureHook2)(dliFailLoadLib,&dli)); | 
|  | if(hmod==0) { | 
|  | PDelayLoadInfo rgpdli[1] = { &dli}; | 
|  | RaiseException(VcppException(ERROR_SEVERITY_ERROR,ERROR_MOD_NOT_FOUND),0,1,PULONG_PTR(rgpdli)); | 
|  | return dli.pfnCur; | 
|  | } | 
|  | } | 
|  | HMODULE hmodT = HMODULE(InterlockedExchangePointer((PVOID *) idd.phmod,PVOID(hmod))); | 
|  | if(hmodT!=hmod) { | 
|  | if(pidd->rvaUnloadIAT) new ULI(pidd); | 
|  | } else ::FreeLibrary(hmod); | 
|  | } | 
|  | dli.hmodCur = hmod; | 
|  | if(__pfnDliNotifyHook2) pfnRet = (*__pfnDliNotifyHook2)(dliNotePreGetProcAddress,&dli); | 
|  | if(pfnRet==0) { | 
|  | if(pidd->rvaBoundIAT && pidd->dwTimeStamp) { | 
|  | PIMAGE_NT_HEADERS pinh(PinhFromImageBase(hmod)); | 
|  | if(pinh->Signature==IMAGE_NT_SIGNATURE && | 
|  | TimeStampOfImage(pinh)==idd.dwTimeStamp && | 
|  | FLoadedAtPreferredAddress(pinh,hmod)) { | 
|  | pfnRet = FARPROC(UINT_PTR(idd.pBoundIAT[iIAT].u1.Function)); | 
|  | if(pfnRet!=0) goto SetEntryHookBypass; | 
|  | } | 
|  | } | 
|  | pfnRet = ::GetProcAddress(hmod,dli.dlp.szProcName); | 
|  | } | 
|  | if(pfnRet==0) { | 
|  | dli.dwLastError = ::GetLastError(); | 
|  | if(__pfnDliFailureHook2) pfnRet = (*__pfnDliFailureHook2)(dliFailGetProc,&dli); | 
|  | if(pfnRet==0) { | 
|  | PDelayLoadInfo rgpdli[1] = { &dli}; | 
|  | RaiseException(VcppException(ERROR_SEVERITY_ERROR,ERROR_PROC_NOT_FOUND),0,1,PULONG_PTR(rgpdli)); | 
|  | pfnRet = dli.pfnCur; | 
|  | } | 
|  | } | 
|  | SetEntryHookBypass: | 
|  | *ppfnIATEntry = pfnRet; | 
|  | HookBypass: | 
|  | if(__pfnDliNotifyHook2) { | 
|  | dli.dwLastError = 0; | 
|  | dli.hmodCur = hmod; | 
|  | dli.pfnCur = pfnRet; | 
|  | (*__pfnDliNotifyHook2)(dliNoteEndProcessing,&dli); | 
|  | } | 
|  | return pfnRet; | 
|  | } | 
|  |  | 
|  | extern "C" | 
|  | WINBOOL WINAPI __FUnloadDelayLoadedDLL2(LPCSTR szDll) { | 
|  | WINBOOL fRet = FALSE; | 
|  | PUnloadInfo pui = __puiHead; | 
|  |  | 
|  | for(pui = __puiHead;pui;pui = pui->puiNext) { | 
|  | LPCSTR szName = PFromRva<LPCSTR>(pui->pidd->rvaDLLName); | 
|  | size_t cbName = __strlen(szName); | 
|  | if(cbName==__strlen(szDll) && __memcmp(szDll,szName,cbName)==0) break; | 
|  | } | 
|  | if(pui && pui->pidd->rvaUnloadIAT) { | 
|  | PCImgDelayDescr pidd = pui->pidd; | 
|  | HMODULE *phmod = PFromRva<HMODULE*>(pidd->rvaHmod); | 
|  | HMODULE hmod = *phmod; | 
|  | OverlayIAT(PFromRva<PImgThunkData>(pidd->rvaIAT),PFromRva<PCImgThunkData>(pidd->rvaUnloadIAT)); | 
|  | ::FreeLibrary(hmod); | 
|  | *phmod = NULL; | 
|  | delete reinterpret_cast<ULI*> (pui); | 
|  | fRet = TRUE; | 
|  | } | 
|  | return fRet; | 
|  | } | 
|  |  | 
|  | extern "C" | 
|  | HRESULT WINAPI __HrLoadAllImportsForDll(LPCSTR szDll) { | 
|  | HRESULT hrRet = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND); | 
|  | PIMAGE_NT_HEADERS pinh = PinhFromImageBase(HMODULE(&__ImageBase)); | 
|  | if(pinh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size) { | 
|  | PCImgDelayDescr pidd; | 
|  | pidd = PFromRva<PCImgDelayDescr>(pinh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress); | 
|  | while(pidd->rvaDLLName) { | 
|  | LPCSTR szDllCur = PFromRva<LPCSTR>(pidd->rvaDLLName); | 
|  | size_t cchDllCur = __strlen(szDllCur); | 
|  | if(cchDllCur==__strlen(szDll) && __memcmp(szDll,szDllCur,cchDllCur)==0) break; | 
|  | pidd++; | 
|  | } | 
|  | if(pidd->rvaDLLName) { | 
|  | FARPROC *ppfnIATEntry = PFromRva<FARPROC*>(pidd->rvaIAT); | 
|  | size_t cpfnIATEntries = CountOfImports(PCImgThunkData(ppfnIATEntry)); | 
|  | FARPROC *ppfnIATEntryMax = ppfnIATEntry + cpfnIATEntries; | 
|  | for(;ppfnIATEntry < ppfnIATEntryMax;ppfnIATEntry++) { | 
|  | __delayLoadHelper2(pidd,ppfnIATEntry); | 
|  | } | 
|  | hrRet = S_OK; | 
|  | } | 
|  | } | 
|  | return hrRet; | 
|  | } |