首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >动态链接库中的SetDllDirectory LoadLibrary

动态链接库中的SetDllDirectory LoadLibrary
EN

Stack Overflow用户
提问于 2014-07-28 16:13:40
回答 3查看 8.9K关注 0票数 0

我可以使用C++ SetDllDirectoryLoadLibrary命令在C++ DLL中加载另一个DLL吗?我试过像这样使用它们:

可执行文件调用第一个DLL,然后第一个DLL加载第二个DLL,然后第二个DLL进行计算.

但是,当我运行可执行文件时,我会收到以下错误消息:

此应用程序请求运行时以一种不寻常的方式终止它。更多信息请与应用程序支持小组联系。

第二DLL工作良好时,直接链接到可执行!

这是我可执行文件中的代码:

代码语言:javascript
复制
#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中的代码:

代码语言:javascript
复制
#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);
        }
    }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-07-28 16:45:14

代码中有一些东西可能导致失败:

  1. 如果无法加载DLL,则不退出:
  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的任何操作都将无效。

总之,除非你能保证

  1. 您正在使用完全相同版本的编译器和编译器选项构建模块和DLL。
  2. 您正在将所有模块链接到运行时库的DLL版本。

然后,将std::string作为参数传递,通常,传递任何维护动态分配内存的对象,都可能或将导致运行时错误。

票数 3
EN

Stack Overflow用户

发布于 2014-07-28 17:03:21

除了错误处理不足和跨模块库使用标准库之外,还有两件事要考虑。

我可以在dll中使用SetDllDirectory来. ?

是的,你可以,但你不应该!(虫子等着发生)。

为什么?因为唯一对环境变化负责的实体是主应用程序。库代码(静态或dll)不知道它将在哪个应用程序中使用。它可能在某些程序中正确工作,而在其他程序中可能失败。

我可以使用dll中的C++ LoadLibrary/FreeLibrary来. ?

是的,您可以,但是不要在dllmain函数中使用它们,因为它会锁住您的程序。

票数 1
EN

Stack Overflow用户

发布于 2014-07-28 18:14:33

我解决了这个问题,并在这里演示了如何:

为了考虑错误处理,我修改了可执行文件和第一个DLL中的代码,并添加了"return 0;“,现在添加到第一个DLL的可执行链接,它的工作原理非常完美…事实上,问题是main需要return一些东西.我把所有的"std::string“和"char*”放在DLL boundaries...By上,我想开发两个DLL,并且在第一个DLL中使用"SetDllDirectory“,原因是我想用C# GUI调用一个DLL,问题是C#中没有可用的"SetDllDirectory”命令,因此,我想到了在第一个DLL中开发两个DLL的想法,我将使用"SetDllDirectory“来处理所需的依赖项(DLL依赖于Octave和Octave Bin目录),然后我开发了第二个DLL来执行实际的计算……我知道有一些像"[DllImport("Kernel32.dll")]”这样的方法,我们可以在C#中使用"SetDllDirectory“,但是这个方法看起来很痛苦。

可执行文件中的更正代码:

代码语言:javascript
复制
    #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中的更正代码:

代码语言:javascript
复制
    #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
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24999520

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档