Динамическая загрузка библиотек Leadtools

Я использую 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 показывает диалоговое окно:

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

Кто-нибудь знает, как я могу это исправить?

Спасибо
Сэм

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 работают правильно. Если вы все еще не можете понять это, вы можете обратиться в нашу службу технической поддержки, чтобы помочь вам решить эту проблему по адресу [email protected]

0

Другие решения

Я не смог заставить динамическую загрузку работать вообще, но я смог использовать Задержка загрузки работать.
Мне нужно было вернуться к связыванию извлеченных файлов .Lib с моим приложением, а затем указать компилятору с задержкой загрузить связанные библиотеки DLL, что дало мне возможность создать Крючки для уведомлений в __pfnDliNotifyHook2 а также __pfnDliFailureHook2 и таким образом я мог бы использовать LoadLibrary загрузить отложенные загруженные Dlls из правильного местоположения.
Но это решило только половину проблемы, потому что некоторые из этих библиотек DLL зависят от других библиотек DLL, и когда я использовал полный путь для загрузки нужной библиотеки DLL, она не смогла найти вторичные библиотеки DLL (которые были расположены в том же каталоге, что и библиотека DLL). Я загружал), и это приведет к ошибке LoadLibrary. Решение состояло в том, чтобы отслеживать эти зависимости и предварительно загружать их. Я включил часть кода, чтобы исправить проблему для тех, кто может столкнуться с подобной ситуацией позже.
П.С. я использую Embarcadero в C ++ Builder, поэтому некоторые из объектов, таких как Strings, TStringList а также Exception может быть не совсем то, что всем знакомо, но концепция должна работать и в 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

По вопросам рекламы [email protected]