2016-10-24 69 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]帮助您解决此问题。