【问题标题】:Dynamic loading Leadtools DLLs动态加载 Leadtools DLL
【发布时间】:2016-10-24 19:35:39
【问题描述】:

我正在使用 Leadtools 17.5。如果我将 Leadtools Dlls 静态链接到我的 64 位 C++ 应用程序,然后调用 L_SetLicenseBuffer 一切正常,返回值为零。但出于安全原因,最终产品不允许将这些 DLL 添加到 System32 文件夹中,也不允许更改系统路径,并且由于多个应用程序正在使用这些工具,我想将它们安装在一个公共文件夹中( C:\Program Files\Common Files\LeadTools\17.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

有谁知道我该如何解决这个问题?

谢谢
山姆

【问题讨论】:

  • 如果我静态链接 Leadtools Dlls -- 你不能在任何东西中静态链接 DLL。您的意思可能是您在项目中使用了导入库。
  • 您应该首先将 DLL 保留在未动态加载它们时工作的相同位置,然后尝试动态加载它们。如果这不起作用,那么问题出在你的代码上,而不是在你的系统中移动东西和利用“AddDllDirectory”。
  • @PaulMcKenzie 我知道。我已经删除了静态链接,只使用动态加载。我想说的是,具有相同参数的相同函数在静态链接时有效,但在我切换到动态加载时会失败。此外,我已将 DLL 添加到开发机器上的 System32 文件夹中。我不能在生产中这样做。
  • 您的术语令人困惑。首先,静态链接模块意味着您正在使用静态库,因此在运行时没有 DLL 发挥作用。如果您使用的是导入库,那不是“静态链接”--。您仍在使用 DLL——导入库仅包含“存根”,它告诉链接器这些函数位于外部模块中。因此,您需要澄清“静态链接”的含义。
  • @PaulMcKenzie 很抱歉造成混乱。有 2 种使用 DLL 的方法,一种是当您链接包含 DLL 名称和存根的给定 DLL 的 .LIB 文件时。据我所知,这称为静态链接 DLL。第二种方法是编译器/链接器对 DLL 一无所知,在代码中您使用 LoadLibrary 加载 DLL 并使用 GetProcAddress 获取函数的地址。这称为动态加载。我试图解释第一个方法返回 SUCCESS 而第二个方法返回 Invalid parameter passing。跨度>

标签: c++ windows dll leadtools-sdk


【解决方案1】:

您需要做的第一件事是检查调试器输出并确保您期望加载的 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 的调用是否正常工作。如果您仍然无法弄清楚,您可以通过 support@leadtools.com 联系我们的技术支持以帮助您解决此问题

【讨论】:

    【解决方案2】:

    我根本无法使动态加载工作,但我能够使用Delay loading 工作。
    我必须做的是返回将提取的 .Lib 文件链接到我的应用程序,然后告诉编译器延迟加载关联的 DLL,这让我有机会创建 Notification Hooks__pfnDliNotifyHook2__pfnDliFailureHook2 这样我就可以使用LoadLibrary 从正确的位置加载延迟加载的 Dll。
    但这只能解决一半的问题,因为其中一些 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 的开头调用以正确设置。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-06
      • 2010-09-30
      • 2013-03-13
      相关资源
      最近更新 更多