动态加载Leadtools dll

Dynamic loading Leadtools DLLs

本文关键字:dll Leadtools 加载 动态      更新时间:2023-10-16

我使用的是Leadtools 17.5。如果我静态地将Leadtools dll链接到我的64位c++应用程序中,然后调用L_SetLicenseBuffer,一切工作正常,返回值为零。但出于安全原因,最终产品不允许将这些DLL添加到System32文件夹中,也不允许更改系统路径,并且由于多个应用程序正在使用我想将它们安装在公共文件夹中的工具(C:Program Files common FilesLeadTools17.5例如),并使用AddDllDirectory将路径添加到DLL搜索路径。因此,我决定在运行时动态加载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显示nag对话框:

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

有人知道我怎么能解决这个问题吗?

谢谢你
山姆

您需要做的第一件事是检查调试器输出,并确保您期望加载的DLL是通过验证路径加载的DLL。在您的搜索路径中可能有多个版本的LTKRNX.DLL。我在这里测试了你的代码,它返回了SUCCESS:

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的调用是否正常工作。如果您仍然不能解决这个问题,您可以联系我们的技术支持,帮助您解决这个问题support@leadtools.com

我根本无法使动态加载工作,但我能够使用延迟加载工作。
我要做的是回到链接提取的。lib文件到我的应用程序,然后告诉编译器加载相关的dll与延迟,这给了我一个机会来创建通知钩子__pfnDliNotifyHook2__pfnDliFailureHook2,这样我可以使用LoadLibrary加载延迟加载dll从正确的位置。
但这只解决了一半的问题,因为其中一些DLL依赖于其他DLL,当我使用完整路径加载我想要的DLL时,它找不到辅助DLL(位于与我加载的目录相同的目录中),这会导致LoadLibrary失败。解决方案是跟踪这些依赖项并预加载它们。我包含了一些代码,以解决以后可能遇到类似情况的任何人的问题。
P。S.我正在使用Embarcadero的c++ Builder,所以一些对象,如Strings, TStringListException可能不是每个人都熟悉的,但这个概念应该在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的开头调用,以正确设置。