2016-10-24 70 views
1

我正在使用Leadtools 17.5。如果我將Leadtools Dll靜態鏈接到我的64位C++應用程序中,然後調用L_SetLicenseBuffer,則一切正常,返回值爲零。但出於安全原因,最終產品不允許將這些DLL添加到System32文件夾中,也不允許更改系統路徑,並且由於多個應用程序正在使用這些工具,我想將它們安裝到一個公用文件夾中(C:\ Program Files \ Common Files \ LeadTools \ 17.5例如)並使用AddDllDirectory將路徑添加到DLL搜索路徑。所以我決定在運行時動態加載DLL。所以,我創建了一個定義這樣的功能:動態加載Leadtools DLL

typedef L_INT (EXT_FUNCTION* TL_SetLicenseBuffer)(L_UCHAR* pLicenseBuffer, L_SSIZE_T nSize, L_TCHAR* pszDeveloperKey); 
typedef L_BOOL (EXT_FUNCTION* TL_IsSupportLocked)(L_UINT uType); 

然後創建一個函數指針像這樣:

TL_SetLicenseBuffer pfSetLicenseBuffer = NULL; 
TL_IsSupportLocked pfIsSupportLocked = NULL; 

然後將路徑添加到這些DLL是DLL搜索路徑,其中:

AddDllDirectory(LEAD_DLL_PATH); 
AddDllDirectory(LEAD_FILTER_PATH); 

,併爲將要在用戶定義的DLL文件的默認目錄搜索路徑:

SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_USER_DIRS); 

然後加載DLL並獲得我所需要的功能地址:

HINSTANCE hKrn = LoadLibrary(L"ltkrnx.dll"); 
pfSetLicenseBuffer = (TL_SetLicenseBuffer)GetProcAddress(hKrn, "L_SetLicenseBuffer"); 
pfIsSupportLocked = (TL_IsSupportLocked)GetProcAddress(hKrn, "L_IsSupportLocked"); 
現在

如果我像以前一樣使用函數指針有相同的參數,函數失敗並返回-13和任何後續調用以pfIsSupportLocked爲例說明了對話框:

retCode = pfSetLicenseBuffer(pLicenseData, LicSize, pKeyStr); // retCode is -13 
pfIsSupportLocked(L_SUPPORT_DOCUMENT); // Shows nag dialog 

有沒有人知道我該如何解決這個問題?

謝謝
山姆

+0

*如果我靜態鏈接Leadtools Dll * - 您無法靜態鏈接任何DLL的DLL。你可能的意思是你在你的項目中使用了導入庫。 – PaulMcKenzie

+0

您應該首先將DLL保存在您未動態加載它們的同一地點,並嘗試動態加載它們。如果這不起作用,那麼問題出在您的代碼上,而不是在系統周圍移動並使用「AddDllDirectory」。 – PaulMcKenzie

+0

@PaulMcKenzie我知道。我已經刪除了靜態鏈接,並且只使用動態加載。我試圖說的是,靜態鏈接時,具有相同參數的功能相同,但當切換到動態加載時會失敗。另外我還將DLL添加到開發機器的System32文件夾中。我無法在生產中做到這一點。 – Sam

回答

0

我無法使動態加載工作,但我可以使用Delay loading工作。
我有什麼做的是回到提取的.lib文件鏈接到我的應用程序,然後告訴編譯器加載與延遲相關的DLL,這給了我一個機會,創造Notification Hooks__pfnDliNotifyHook2__pfnDliFailureHook2和那種方式我可以使用LoadLibrary從正確的位置加載延遲加載的Dll。
但是,只解決了一半的問題,因爲這些Dll中的一些依賴於其他DLL,並且當我使用完整路徑加載我想要的DLL時,它無法找到輔助DLL(它們位於與一個我正在加載),這會導致LoadLibrary失敗。解決方案是跟蹤這些依賴關係並預先加載它們。我將包含一些代碼,以解決稍後可能遇到類似情況的任何人的問題。
P. S.我使用Embarcadero公司的C++ Builder的,所以有些像StringsTStringListException對象可能不正是大家所熟悉的,但這個概念應該在VC++以及工作。

#include <map> 

struct TDllDependency 
{ 
    TStringList* Dependency; 
    HMODULE hDll; 

    __fastcall TDllDependency(void) 
    { 
     hDll = NULL; 
     Dependency = new TStringList(); 
    } 
    virtual __fastcall ~TDllDependency(void) 
    { 
     delete Dependency; 
    } 
}; 

class TDllModList : public std::map<System::String, TDllDependency> 
{ 
public: 
    void __fastcall CheckDependency(const System::String& aName); 
}; 
//--------------------------------------------------------------------------- 
System::String __fastcall GetLtDllPath(void) 
{ 
    wchar_t* pfPath = NULL; 
    System::String dllPath; 

    SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, KF_FLAG_DEFAULT, NULL, &pfPath); 
    if (NULL != pfPath) 
    { 
     dllPath = IncludeTrailingBackslash(pfPath) + L"LeadTools\\17.5\\"; 
     ::CoTaskMemFree(pfPath); 
    } 
    return dllPath; 
} 
System::String mDllPath(GetLtDllPath()); 
TDllModList DllModList; 
void __fastcall InitDllDepends() 
{ 
    DllModList.clear(); 
#if defined(_WIN64) 
    DllModList[L"ltimgefxx.dll"].Dependency->CommaText = L"ltdisx.dll,ltimgutlx.dll"; 
    DllModList[L"ltefxx.dll"].Dependency->CommaText = L"ltdisx.dll,ltimgutlx.dll"; 
    DllModList[L"ltimgcorx.dll"].Dependency->CommaText = L"ltdisx.dll,ltimgutlx.dll"; 
    DllModList[L"ltdlgimgefxx.dll"].Dependency->CommaText = L"ltdisx.dll,ltdlgkrnx.dll,ltdlgcomx.dll,ltdlgctrlx.dll,ltdlgutlx.dll,ltimgefxx.dll,ltimgsfxx.dll,ltimgcorx.dll,ltimgclrx.dll"; 
    DllModList[L"ltdlgutlx.dll"].Dependency->CommaText = L"ltdisx.dll,ltfilx.dll,ltdlgkrnx.dll,ltimgclrx.dll,ltimgcorx.dll,ltimgefxx.dll,ltimgsfxx.dll"; 
    DllModList[L"ltdlgctrlx.dll"].Dependency->CommaText = L"ltdlgutlx.dll,ltdlgkrnx.dll,ltdisx.dll,ltfilx.dll,ltimgefxx.dll"; 
    DllModList[L"ltdlgcomx.dll"].Dependency->CommaText = L"ltdlgkrnx.dll,ltdlgctrlx.dll,ltdlgutlx.dll"; 
#elif defined(__WIN32__) 
    DllModList[L"ltimgefxu.dll"].Dependency->CommaText = L"ltdisu.dll,ltimgutlu.dll"; 
    DllModList[L"ltefxu.dll"].Dependency->CommaText = L"ltdisu.dll,ltimgutlu.dll"; 
    DllModList[L"ltimgcoru.dll"].Dependency->CommaText = L"ltdisu.dll,ltimgutlu.dll"; 
    DllModList[L"ltdlgimgefxu.dll"].Dependency->CommaText = L"ltdisu.dll,ltdlgkrnu.dll,ltdlgcomu.dll,ltdlgctrlu.dll,ltdlgutlu.dll,ltimgefxu.dll,ltimgsfxu.dll,ltimgcoru.dll,ltimgclru.dll"; 
    DllModList[L"ltdlgutlu.dll"].Dependency->CommaText = L"ltdisu.dll,ltfilu.dll,ltdlgkrnu.dll,ltimgclru.dll,ltimgcoru.dll,ltimgefxu.dll,ltimgsfxu.dll"; 
    DllModList[L"ltdlgctrlu.dll"].Dependency->CommaText = L"ltdlgutlu.dll,ltdlgkrnu.dll,ltdisu.dll,ltfilu.dll,ltimgefxu.dll"; 
    DllModList[L"ltdlgcomu.dll"].Dependency->CommaText = L"ltdlgkrnu.dll,ltdlgctrlu.dll,ltdlgutlu.dll"; 
#endif 
}; 
HMODULE SafeLoadLeadDll(const System::String tName) 
{ 
    System::String tPath; 
    HMODULE retVal = NULL; 

    DllModList.CheckDependency(tName); 
    tPath = mDllPath + tName; 
    if(FileExists(tPath)) 
     retVal = ::LoadLibrary(tPath.c_str()); 
    return retVal; 
} 
FARPROC WINAPI MyDliNotifyHook(unsigned dliNotify, PDelayLoadInfo pdli) 
{ 
    FARPROC retVal = NULL; 
    System::String tStr(pdli->szDll); 

    tStr = tStr.LowerCase(); 
    if(dliNotePreLoadLibrary == dliNotify) 
    { 
     TDllModList::iterator i = DllModList.find(tStr); 

     if(DllModList.end() == i) 
     { 
      retVal = (FARPROC)SafeLoadLeadDll(tStr); 
      DllModList[tStr].hDll = (HMODULE)retVal; 
     } 
     else if(NULL == i->second.hDll) 
     { 
      i->second.hDll = SafeLoadLeadDll(tStr); 
      retVal = (FARPROC)i->second.hDll; 
     } 
     else 
      retVal = (FARPROC)i->second.hDll; 
    } 
    else if(dliFailLoadLib == dliNotify) 
    { 
     tStr = L"Compleatly falied to load " + tStr; 
     ::OutputDebugString(tStr.c_str()); 
    } 
    return retVal; 
} 

FARPROC WINAPI MyDliFailureHook(unsigned dliNotify, PDelayLoadInfo pdli) 
{ 
    FARPROC retVal = NULL; 
    if(dliNotePreLoadLibrary == dliNotify) 
    { 
     System::String tMsg = pdli->szDll; 

     tMsg = L"Failed to load \"" + tMsg + L"\".\n" + SysErrorMessage(::GetLastError()); 
     throw Exception(tMsg); 
    } 
    return retVal; 
} 

extern "C" PfnDliHook __pfnDliNotifyHook2 = MyDliNotifyHook; 
extern "C" PfnDliHook __pfnDliFailureHook2 = MyDliFailureHook; 
void __fastcall TDllModList::CheckDependency(const System::String& aName) 
{ 
    TDllModList::iterator i = find(aName); 

    if(end() != i) 
    { 
     int len = i->second.Dependency->Count; 
     int j; 
     System::String tPath; 

     for(j = 0; j < len; j++) 
     { 
      if(end() == find(i->second.Dependency->Strings[j])) 
      { 
       CheckDependency(i->second.Dependency->Strings[j]); 
       tPath = mDllPath + i->second.Dependency->Strings[j]; 
       (*this)[i->second.Dependency->Strings[j]].hDll = ::LoadLibrary(tPath.c_str()); 
      } 
     } 
    } 
} 
//--------------------------------------------------------------------------- 

當然InitDllDepends();,並應在WinMain開始被要求正確設置好了。

0

你需要做的第一件事是檢查調試器輸出,並確保你期望得到加載的DLL是通過驗證的路徑越來越加載的一個。您的搜索路徑中可能有多個版本的LTKRNX.DLL。我在這裏測試你的代碼,並返回成功:

typedef L_INT (EXT_FUNCTION* TL_SetLicenseBuffer)(L_UCHAR* pLicenseBuffer, L_SSIZE_T nSize, L_TCHAR* pszDeveloperKey); 
typedef L_BOOL (EXT_FUNCTION* TL_IsSupportLocked)(L_UINT uType); 

HINSTANCE hKrn = LoadLibrary(L"ltkrnx.dll"); 
TL_SetLicenseBuffer pfSetLicenseBuffer = NULL; 
TL_IsSupportLocked pfIsSupportLocked = NULL; 

pfSetLicenseBuffer = (TL_SetLicenseBuffer)GetProcAddress(hKrn, "L_SetLicenseBuffer"); 
pfIsSupportLocked = (TL_IsSupportLocked)GetProcAddress(hKrn, "L_IsSupportLocked"); 

L_INT retCode = pfSetLicenseBuffer(szLICAnsi, _countof(szLICAnsi), pKeyStr); 
if(retCode == SUCCESS) 
    bRet = pfIsSupportLocked(L_SUPPORT_DOCUMENT); 
else 
    printf("Problem!"); 

還什麼PaulMcKenzie建議是另一種方式來驗證你給LoadLibrary調用正常工作。如果您仍然無法解決問題,可以聯繫我們的技術支持部門,通過[email protected]幫助您解決此問題。