/*------ * Module: loadlib.c * * Description: This module contains routines related to * delay load import libraries. * * Comments: See "readme.txt" for copyright and license information. *------- */ #include #include #include #ifndef WIN32 #include #endif /* WIN32 */ #include "loadlib.h" #include "pgenlist.h" #include "misc.h" #ifdef WIN32 #ifdef _MSC_VER #pragma comment(lib, "Delayimp") #ifdef _HANDLE_ENLIST_IN_DTC_ #ifdef UNICODE_SUPPORT #pragma comment(lib, "pgenlist") #else #pragma comment(lib, "pgenlista") #endif /* UNICODE_SUPPORT */ #endif /* _HANDLE_ENLIST_IN_DTC_ */ // The followings works under VC++6.0 but doesn't work under VC++7.0. // Please add the equivalent linker options using command line etc. #if (_MSC_VER == 1200) && defined(DYNAMIC_LOAD) // VC6.0 #ifdef UNICODE_SUPPORT #pragma comment(linker, "/Delayload:pgenlist.dll") #else #pragma comment(linker, "/Delayload:pgenlista.dll") #endif /* UNICODE_SUPPORT */ #pragma comment(linker, "/Delay:UNLOAD") #endif /* _MSC_VER */ #endif /* _MSC_VER */ #if defined(DYNAMIC_LOAD) #define WIN_DYN_LOAD #ifdef UNICODE_SUPPORT CSTR pgenlist = "pgenlist"; CSTR pgenlistdll = "pgenlist.dll"; CSTR psqlodbc = "psqlodbc35w"; CSTR psqlodbcdll = "psqlodbc35w.dll"; #else CSTR pgenlist = "pgenlista"; CSTR pgenlistdll = "pgenlista.dll"; CSTR psqlodbc = "psqlodbc30a"; CSTR psqlodbcdll = "psqlodbc30a.dll"; #endif /* UNICODE_SUPPORT */ #if defined(_MSC_VER) && (_MSC_VER >= 1200) #define _MSC_DELAY_LOAD_IMPORT #endif /* MSC_VER */ #endif /* DYNAMIC_LOAD */ #endif /* WIN32 */ #if defined(_MSC_DELAY_LOAD_IMPORT) /* * Error hook function for delay load import. * Try to load a DLL based on psqlodbc path. */ #if (_MSC_VER >= 1900) /* vc14 or later */ #define TRY_DLI_HOOK \ __try { #define RELEASE_NOTIFY_HOOK #elif (_MSC_VER < 1300) /* vc6 */ extern PfnDliHook __pfnDliFailureHook; extern PfnDliHook __pfnDliNotifyHook; #define TRY_DLI_HOOK \ __try { \ __pfnDliFailureHook = DliErrorHook; \ __pfnDliNotifyHook = DliErrorHook; #define RELEASE_NOTIFY_HOOK \ __pfnDliNotifyHook = NULL; #else /* vc7 ~ 12 */ extern PfnDliHook __pfnDliFailureHook2; extern PfnDliHook __pfnDliNotifyHook2; #define TRY_DLI_HOOK \ __try { \ __pfnDliFailureHook2 = DliErrorHook; \ __pfnDliNotifyHook2 = DliErrorHook; #define RELEASE_NOTIFY_HOOK \ __pfnDliNotifyHook2 = NULL; #endif /* _MSC_VER */ #else #define TRY_DLI_HOOK \ __try { #define RELEASE_NOTIFY_HOOK #endif /* _MSC_DELAY_LOAD_IMPORT */ #if defined(_MSC_DELAY_LOAD_IMPORT) static BOOL loaded_pgenlist = FALSE; static HMODULE enlist_module = NULL; static BOOL loaded_psqlodbc = FALSE; /* * Load a DLL based on psqlodbc path. */ HMODULE MODULE_load_from_psqlodbc_path(const char *module_name) { extern HINSTANCE s_hModule; HMODULE hmodule = NULL; char szFileName[MAX_PATH]; if (GetModuleFileName(s_hModule, szFileName, sizeof(szFileName)) > 0) { char drive[_MAX_DRIVE], dir[_MAX_DIR], sysdir[MAX_PATH]; _splitpath(szFileName, drive, dir, NULL, NULL); GetSystemDirectory(sysdir, MAX_PATH); SPRINTF_FIXED(szFileName, "%s%s%s.dll", drive, dir, module_name); if (_strnicmp(szFileName, sysdir, strlen(sysdir)) != 0) { hmodule = LoadLibraryEx(szFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); MYLOG(0, "psqlodbc path based %s loaded module=%p\n", module_name, hmodule); } } return hmodule; } static FARPROC WINAPI DliErrorHook(unsigned dliNotify, PDelayLoadInfo pdli) { HMODULE hmodule = NULL; const char* call_module = NULL; MYLOG(0, "Dli%sHook %s Notify=%d\n", (dliFailLoadLib == dliNotify || dliFailGetProc == dliNotify) ? "Error" : "Notify", NULL != pdli->szDll ? pdli->szDll : pdli->dlp.szProcName, dliNotify); switch (dliNotify) { case dliNotePreLoadLibrary: case dliFailLoadLib: RELEASE_NOTIFY_HOOK if (_strnicmp(pdli->szDll, pgenlist, strlen(pgenlist)) == 0) call_module = pgenlist; else if (_strnicmp(pdli->szDll, psqlodbc, strlen(psqlodbc)) == 0) call_module = psqlodbc; if (call_module) { if (hmodule = MODULE_load_from_psqlodbc_path(call_module), NULL == hmodule) hmodule = LoadLibrary(call_module); if (NULL != hmodule) { if (pgenlist == call_module) loaded_pgenlist = TRUE; else if (psqlodbc == call_module) loaded_psqlodbc = TRUE; } } break; } return (FARPROC) hmodule; } void AlreadyLoadedPsqlodbc(void) { loaded_psqlodbc = TRUE; } /* * unload delay loaded libraries. */ typedef BOOL (WINAPI *UnloadFunc)(LPCSTR); void CleanupDelayLoadedDLLs(void) { BOOL success; #if (_MSC_VER < 1300) /* VC6 DELAYLOAD IMPORT */ UnloadFunc func = __FUnloadDelayLoadedDLL; #else UnloadFunc func = __FUnloadDelayLoadedDLL2; #endif /* The dll names are case sensitive for the unload helper */ if (loaded_pgenlist) { if (enlist_module != NULL) { MYLOG(0, "Freeing Library %s\n", pgenlistdll); FreeLibrary(enlist_module); } MYLOG(0, "%s unloading\n", pgenlistdll); success = (*func)(pgenlistdll); MYLOG(0, "%s unloaded success=%d\n", pgenlistdll, success); loaded_pgenlist = FALSE; } if (loaded_psqlodbc) { MYLOG(0, "%s unloading\n", psqlodbcdll); success = (*func)(psqlodbcdll); MYLOG(0, "%s unloaded success=%d\n", psqlodbcdll, success); loaded_psqlodbc = FALSE; } return; } #else void CleanupDelayLoadedDLLs(void) { return; } #endif /* _MSC_DELAY_LOAD_IMPORT */ #ifdef _HANDLE_ENLIST_IN_DTC_ RETCODE CALL_EnlistInDtc(ConnectionClass *conn, void *pTra, int method) { RETCODE ret; BOOL loaded = TRUE; #if defined(_MSC_DELAY_LOAD_IMPORT) if (!loaded_pgenlist) { TRY_DLI_HOOK ret = EnlistInDtc(conn, pTra, method); } __except ((GetExceptionCode() & 0xffff) == ERROR_MOD_NOT_FOUND ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { if (enlist_module = MODULE_load_from_psqlodbc_path(pgenlist), NULL == enlist_module) loaded = FALSE; else ret = EnlistInDtc(conn, pTra, method); } if (loaded) loaded_pgenlist = TRUE; RELEASE_NOTIFY_HOOK } else ret = EnlistInDtc(conn, pTra, method); #else ret = EnlistInDtc(conn, pTra, method); loaded_pgenlist = TRUE; #endif /* _MSC_DELAY_LOAD_IMPORT */ return ret; } RETCODE CALL_DtcOnDisconnect(ConnectionClass *conn) { if (loaded_pgenlist) return DtcOnDisconnect(conn); return FALSE; } RETCODE CALL_IsolateDtcConn(ConnectionClass *conn, BOOL continueConnection) { if (loaded_pgenlist) return IsolateDtcConn(conn, continueConnection); return FALSE; } void *CALL_GetTransactionObject(HRESULT *hres) { void *ret = NULL; BOOL loaded = TRUE; #if defined(_MSC_DELAY_LOAD_IMPORT) if (!loaded_pgenlist) { TRY_DLI_HOOK ret = GetTransactionObject(hres); } __except ((GetExceptionCode() & 0xffff) == ERROR_MOD_NOT_FOUND ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { if (enlist_module = MODULE_load_from_psqlodbc_path(pgenlist), NULL == enlist_module) loaded = FALSE; else ret = GetTransactionObject(hres); } if (loaded) loaded_pgenlist = TRUE; RELEASE_NOTIFY_HOOK } else ret = GetTransactionObject(hres); #else ret = GetTransactionObject(hres); loaded_pgenlist = TRUE; #endif /* _MSC_DELAY_LOAD_IMPORT */ return ret; } void CALL_ReleaseTransactionObject(void *pObj) { if (loaded_pgenlist) ReleaseTransactionObject(pObj); return; } #endif /* _HANDLE_ENLIST_IN_DTC_ */