Могу ли я использовать 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);
}
}
}
В вашем коде есть несколько вещей, которые могут вызвать сбой:
За 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 будет недействительной из-за различий в куче памяти.
Итак, в двух словах, если вы не можете гарантия тот
Потом прохождение std::string
в качестве параметра и, как правило, передача любого объекта, который поддерживает динамически выделяемую память, может или приведет к ошибкам во время выполнения.
Помимо неадекватной обработки ошибок и использования стандартной библиотеки в разных модулях, необходимо учитывать еще два момента.
Могу ли я использовать SetDllDirectory в DLL для …?
Да, вы можете, но вы не должны! (Ошибки ждут, чтобы произойти).
Зачем ? потому что единственным объектом, который отвечает за изменение среды, является основное приложение.
Библиотечный код (статический или dll) не знает, в каком приложении он будет использоваться.
Он может работать правильно в некоторых программах и может не работать в других.
Могу ли я использовать C ++ LoadLibrary / FreeLibrary в DLL для …?
Да, вы можете, но не используйте их в функции dllmain, так как она может заблокировать вашу программу.
Я решил проблему, и показал, как здесь:
Я изменил код внутри исполняемого файла и 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);
}
}
}