SetDllDirectory LoadLibrary inside a DLL

我怕爱的太早我们不能终老 提交于 2019-12-02 13:19:47

There are a few things in your code that can cause failure:

  1. You do not exit if the DLL cannot be loaded:
  2. You are passing objects that internally use dynamic allocation, and thus will use the heap manager.

For 1. above, your main() function only does a simple cout if the library cannot be found. However instead of exiting, the main function proceeds as if the library was found.

For 2. above, passing std::string as a parameter to a DLL function is error prone and not recommended unless you know exactly what you're doing. The reason it is error prone is

  • The DLL that contains the function call may have been built with a different set of options than the DLL that calls the function. These differing options could cause a difference in the way that std::string is implemeted, how it's layed out in memory, etc.

  • The DLL that contains the function call may have been built by a different version of the compiler than the DLL that calls the function. Again, same issue with differing implementations of std::string

  • The DLL's and modules using std::string may not have been built using the DLL version of the C runtime library. If the DLL's/modules are not built and linked using the DLL version of the runtime library, the DLL will be using a different heap than the module. Any operation on std::string will be invalid, due to differing memory heaps being used.

So in a nutshell, unless you can guarantee that

  1. You are building the modules and DLL's with the exact same version of the compiler and compiler options.
  2. You are linking all modules to the DLL version of the runtime library.

Then passing std::string as a parameter, and in general, passing any object that maintains dynamically allocated memory, may or will lead to runtime errors.

Besides the inadequate error handling and using the standard library across module boudaries ,there are two other things to consider.

Can I use SetDllDirectory in a dll to ... ?

Yes you can ,but you SHOULDN'T ! (BUGS waiting to happen).

Why ? because the only entity that is responsable for changing environment is the main-application. Library code (static or dll) doesn't know in which application it's going to be used. It might work correctly in some programs and it may fail in others.

Can I use C++ LoadLibrary/FreeLibrary in a dll to ... ?

Yes you can ,but don't use them in the dllmain function since it can deadlock your program.

I solved the problem, and showed how here:

I changed the code inside executable and 1st DLL like below, to consider error handling, and also I added the "return 0;" now the executable links to 1st DLL and it works perfect... Actually the problem was that main needed to return something...I raplaced all the "std::string" with "char*" at the DLL boundaries...By the way, the reason that I want to develop two DLLs and I'm using "SetDllDirectory" inside the 1st one is that I want to call a DLL with a C# GUI, and the problem is that there is no "SetDllDirectory" command available in C#, therefore, I came up with the idea of developing two DLLs, inside first DLL, I will use "SetDllDirectory" to take care of the required dependencies (DLL is dependent on Octave and Octave Bin directory) and then I developed a 2nd DLL which carries out the actual computations...I know that there are some methods like "[DllImport("Kernel32.dll")]" and from there we can use "SetDllDirectory" in C# but that method looks painful.

The corrected code inside executable:

    #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;
}

The corrected code inside 1st 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);
        }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!