我可以在C ++ DLL中使用C ++ SetDllDirectory
和LoadLibrary
命令来加载另一个DLL吗?我试过像这样使用它们:
Executable调用第一个DLL, 然后第一个DLL加载第二个DLL, 然后第二个DLL进行计算...
但是当我运行可执行文件时,我收到此错误消息:
此应用程序已请求Runtime以不寻常的方式终止它。请联系应用程序支持团队以获取更多信息。
第二个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 :(得分:2)
您的代码中有一些可能导致失败的事情:
对于上面的1.
,如果无法找到库,则main()函数只会执行简单的cout
。但是,main
函数不是退出,而是像找到库一样进行。
对于上面的2.
,将std::string
作为参数传递给DLL函数容易出错,除非您知道正好您正在做什么,否则不建议这样做。它容易出错的原因是
包含函数调用的DLL可能使用与调用函数的DLL不同的选项集构建。这些不同的选项可能会导致std::string
的实现方式,内存中的布局等方式出现差异等。
包含函数调用的DLL可能是由与调用该函数的DLL不同的编译器版本构建的。同样,std::string
使用std :: string的DLL和模块可能尚未使用C运行时库的DLL version
构建。如果未使用运行时库的DLL版本构建和链接DLL的/模块,则DLL将使用与模块不同的堆。由于使用了不同的内存堆,对std :: string的任何操作都将无效。
简而言之,除非你能保证
然后将std::string
作为参数传递,并且通常,传递维护动态分配的内存的任何对象,可能或将导致运行时错误。
答案 1 :(得分:1)
除了错误处理不充分以及跨模块boudaries使用标准库外,还有两件事需要考虑。
我可以在dll中使用SetDllDirectory来...?
是的,你可以,但你应该知道! (BUGS等待发生)。
为什么?因为唯一负责改变环境的实体是主要应用程序。 库代码(静态或dll)不知道它将在哪个应用程序中使用。 它可能在某些程序中正常工作,但在其他程序中可能会失败。
我可以在dll中使用C ++ LoadLibrary / FreeLibrary来...?
是的,你可以,但不要在dllmain函数中使用它们,因为它可能使你的程序死锁。
答案 2 :(得分:0)
我解决了问题,并在此处展示:
我更改了可执行文件和第一个DLL中的代码,如下所示,考虑错误处理,我还添加了“return 0;
”现在可执行链接到第一个DLL,它工作正常...实际上问题是那个main
需要return
一些东西......我在DLL边界处用“std::string
”替换了所有“char*
”...顺便说一下,原因是我想开发两个DLL,我在第一个中使用“SetDllDirectory
”是我想用C#GUI调用DLL,问题是没有“SetDllDirectory
”命令在C#中可用,因此,我提出了开发两个DLL的想法,在第一个DLL中,我将使用“SetDllDirectory
”来处理所需的依赖项(DLL依赖于Octave和Octave Bin目录)然后我开发了第二个DLL来执行实际计算...我知道有一些方法,如“[DllImport("Kernel32.dll")]
”,从那里我们可以在C#中使用“SetDllDirectory
”,但该方法看起来痛苦。
可执行文件中的更正代码:
#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;
}
第一个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);
}
}
}