SetDllDirectory LoadLibrary внутри DLL

Могу ли я использовать C ++ SetDllDirectory а также LoadLibrary команды внутри C ++ DLL для загрузки другой DLL? Я пытался использовать их так:

Исполняемый файл вызывает первую DLL,
затем первая DLL загружает вторую DLL,
затем 2-я DLL делает расчеты …

но когда я запускаю исполняемый файл, я получаю это сообщение об ошибке:

Это приложение запросило Runtime прекратить его необычным способом. Пожалуйста, свяжитесь со службой поддержки приложений для получения дополнительной информации.

2-я DLL отлично работает, когда связана непосредственно с исполняемым файлом!

Это код внутри моего исполняемого файла:

#include <windows.h>
#include <iostream>

int main(){
HINSTANCE hDLL_Link=NULL;
SetDllDirectory((LPCWSTR)L"C:\\Users\\MC\\Documents\\2014_07_01a_FDD_VC2008\\test_call_DLL\\EXE_calls_Link_DLL\\Release");
hDLL_Link=LoadLibrary((LPCWSTR)L"Link_DLL.dll");
if(hDLL_Link==NULL) std::cout<<"did not load"<<'\n';
typedef void (*Ptr_OPS_Link)();
Ptr_OPS_Link Ptr_OPS_Link_0;
Ptr_OPS_Link_0=(Ptr_OPS_Link)GetProcAddress(hDLL_Link,"OPS_Link");
Ptr_OPS_Link_0();
FreeLibrary(hDLL_Link);
system("pause");
}

это код внутри первой DLL:

#include "Link.h"
extern "C" __declspec(dllexport)
void OPS_Link(){
Link*Link_Ptr_Object=NULL;
if(Link_Ptr_Object==NULL){
Link_Ptr_Object=new Link();
}
if(Link_Ptr_Object==NULL){
//can not throw inside __declspec(dllexport) functions marked extern "C" that's why std::cout is implemented:
std::cout<<"Error: could not link to FDD DLL"<<'\n';
system("pause");
}
delete Link_Ptr_Object;
Link_Ptr_Object=NULL;
}

Link::Link()
:m_void_Ptr_ObjectByDLL(NULL){
HINSTANCE hDLL=NULL;//handle to DLL
SetDllDirectory((LPCWSTR)L"C:\\Software\\Octave-3.6.1\\bin\\");
hDLL=LoadLibrary((LPCWSTR)L"C:\\Users\\MC\\Documents\\2014_07_01a_FDD_VC2008\\Executable\\Release\\FDD_DLL.dll");
if(hDLL==NULL){
throw "DLL loading could not be done";
}else if(hDLL!=NULL){
typedef void (*Ptr_OPS_FDD)(std::string, int, int);
Ptr_OPS_FDD Ptr_OPS_FDD_0;//pointer to procedure inside DLL
Ptr_OPS_FDD_0=NULL;
Ptr_OPS_FDD_0=(Ptr_OPS_FDD)GetProcAddress(hDLL,"OPS_FDD");
if(Ptr_OPS_FDD_0==NULL){
FreeLibrary(hDLL);
throw "DLL exported function address could not be determined";
}else{
//run the procedure inside DLL:
Ptr_OPS_FDD_0("FDD_INPUT_Truss_Bridge_Data2_Ambient_Inch_11Channels_77824Samples_SamplingFreq_256Hz.txt",11,256);//LabScaleTruss
//Ptr_OPS_FDD_0("FDD_INPUT_Ambient_EW_15Channels_3000Samples_SamplingFreq_20Hz.txt",15,20);//AmbientEW
//Ptr_OPS_FDD_0("FDD_INPUT_Meriden_3Channels(3_5_8)_3686400Samples_SamplingFreq_2048Hz.txt",3,2048);//MeridenBridge
FreeLibrary(hDLL);
}
}
}

0

Решение

В вашем коде есть несколько вещей, которые могут вызвать сбой:

  1. Вы не выходите, если DLL не может быть загружена:
  2. Вы передаете объекты, которые внутренне используют динамическое размещение и, таким образом, будут использовать менеджер кучи.

За 1. выше, ваша функция main () выполняет только простую cout если библиотека не может быть найдена. Однако вместо выхода main Функция продолжается, как будто библиотека была найдена.

За 2. выше, проходя std::string в качестве параметра для функции DLL подвержена ошибкам и не рекомендуется, если вы не знаете именно так что ты делаешь. Причина, по которой он подвержен ошибкам

  • Библиотека DLL, которая содержит вызов функции, может быть построена с другим набором параметров, чем библиотека DLL, которая вызывает функцию. Эти разные варианты могут вызвать разницу в том, как std::string реализовано, как выложено в память и т. д.

  • DLL, содержащая вызов функции, может быть создана другой версией компилятора, чем DLL, которая вызывает функцию. Опять та же проблема с различными реализациями std::string

  • DLL и модули, использующие std :: string, возможно, не были построены с использованием DLL version библиотеки времени выполнения C. Если библиотеки DLL / модули не собраны и не связаны с использованием версии DLL библиотеки времени выполнения, DLL будет использовать кучу, отличную от модуля. Любая операция с std :: string будет недействительной из-за различий в куче памяти.

Итак, в двух словах, если вы не можете гарантия тот

  1. Вы строите модули и DLL с одинаковой версией параметров компилятора и компилятора.
  2. Вы связываете все модули с DLL-версией библиотеки времени выполнения.

Потом прохождение std::string в качестве параметра и, как правило, передача любого объекта, который поддерживает динамически выделяемую память, может или приведет к ошибкам во время выполнения.

2

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

Помимо неадекватной обработки ошибок и использования стандартной библиотеки в разных модулях, необходимо учитывать еще два момента.

Могу ли я использовать SetDllDirectory в DLL для …?

Да, вы можете, но вы не должны! (Ошибки ждут, чтобы произойти).

Зачем ? потому что единственным объектом, который отвечает за изменение среды, является основное приложение.
Библиотечный код (статический или dll) не знает, в каком приложении он будет использоваться.
Он может работать правильно в некоторых программах и может не работать в других.

Могу ли я использовать C ++ LoadLibrary / FreeLibrary в DLL для …?

Да, вы можете, но не используйте их в функции dllmain, так как она может заблокировать вашу программу.

1

Я решил проблему, и показал, как здесь:

Я изменил код внутри исполняемого файла и 1-й DLL, как показано ниже, чтобы учесть обработку ошибок, а также добавил «return 0;«теперь исполняемый файл ссылается на 1-ую DLL и работает отлично … На самом деле проблема была в том main нужно return что-то … Я все «std::string» с «char*«на границах DLL … Кстати, причина, по которой я хочу разработать две библиотеки DLL, и я использую»SetDllDirectory«внутри 1-го я хочу вызвать DLL с C # GUI, и проблема в том, что нет»SetDllDirectory«Команда доступна в C #, поэтому я пришел к идее разработки двух DLL, внутри первой DLL, которую я буду использовать»SetDllDirectory«чтобы позаботиться о необходимых зависимостях (DLL зависит от каталога Octave и Octave Bin), а затем я разработал 2-ую DLL, которая выполняет реальные вычисления … Я знаю, что есть некоторые методы, такие как»[DllImport("Kernel32.dll")]«и оттуда мы можем использовать»SetDllDirectory«в C #, но этот метод выглядит больно.

Исправленный код внутри исполняемого файла:

    #include <windows.h>
#include <iostream>

int main(){
try{
HINSTANCE hDLL_Link=NULL;
hDLL_Link=LoadLibrary((LPCWSTR)L"Link_DLL.dll");
if(hDLL_Link==NULL){
throw "Link DLL did not load";
}else{
typedef void (*Ptr_OPS_Link)();
Ptr_OPS_Link Ptr_OPS_Link_0=NULL;
Ptr_OPS_Link_0=(Ptr_OPS_Link)GetProcAddress(hDLL_Link,"OPS_Link");
if(Ptr_OPS_Link_0==NULL){
throw "Link DLL exported function not found";
FreeLibrary(hDLL_Link);
}else{
Ptr_OPS_Link_0();
FreeLibrary(hDLL_Link);
}
}
}
catch(char*char_Ptr_Exception){
std::cerr<<"Error: "<<char_Ptr_Exception<<'\n';
}
system("pause");
return 0;
}

Исправленный код внутри 1-й DLL:

    #include "Link.h"
extern "C" __declspec(dllexport)
void OPS_Link(){
Link*Link_Ptr_Object=NULL;
if(Link_Ptr_Object==NULL){
Link_Ptr_Object=new Link();
}
if(Link_Ptr_Object==NULL){
////can not throw inside __declspec(dllexport) functions marked extern "C" that's why std::cout is implemented:
//std::cout<<"Error: could not link to FDD DLL"<<'\n';
system("pause");
}
delete Link_Ptr_Object;
Link_Ptr_Object=NULL;
}

Link::Link()
:m_void_Ptr_ObjectByDLL(NULL){
HINSTANCE hDLL=NULL;//handle to DLL
SetDllDirectory((LPCWSTR)L"C:\\Software\\Octave-3.6.1\\bin\\");
//path relative to executable (C# executable or C++ executable)
hDLL=LoadLibrary((LPCWSTR)L"FDD_DLL.dll");
if(hDLL==NULL){
throw "FDD DLL did not load";
}else if(hDLL!=NULL){
typedef void (*Ptr_OPS_FDD)(char*, int, int);
Ptr_OPS_FDD Ptr_OPS_FDD_0;//pointer to procedure inside DLL
Ptr_OPS_FDD_0=NULL;
Ptr_OPS_FDD_0=(Ptr_OPS_FDD)GetProcAddress(hDLL,"OPS_FDD");
if(Ptr_OPS_FDD_0==NULL){
throw "FDD DLL exported function not found";
FreeLibrary(hDLL);
}else{
//run the procedure inside DLL:
Ptr_OPS_FDD_0("FDD_INPUT_Truss_Bridge_Data2_Ambient_Inch_11Channels_77824Samples_SamplingFreq_256Hz.txt",11,256);//LabScaleTruss
//Ptr_OPS_FDD_0("FDD_INPUT_Ambient_EW_15Channels_3000Samples_SamplingFreq_20Hz.txt",15,20);//AmbientEW
//Ptr_OPS_FDD_0("FDD_INPUT_Meriden_3Channels(3_5_8)_3686400Samples_SamplingFreq_2048Hz.txt",3,2048);//MeridenBridge
FreeLibrary(hDLL);
}
}
}
0
По вопросам рекламы [email protected]