0

SetDllDirectoryC++ DLL 内で C++とコマンドを使用LoadLibraryして別の DLL をロードできますか? 私は次のようにそれらを使用してみました:

実行可能ファイルが最初の DLL を呼び出し、次に 1 番目の DLL が 2 番目の DLL をロードし、次に 2 番目の DLL が計算を行います...

しかし、実行可能ファイルを実行すると、次のエラー メッセージが表示されます。

このアプリケーションは、異常な方法で終了するようランタイムに要求しました。詳細については、アプリケーション サポート チームにお問い合わせください。

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);
        }
    }
}
4

3 に答える 3

2

コードには、失敗の原因となる可能性のあるものがいくつかあります。

  1. DLL をロードできない場合は終了しません。
  2. 内部で動的割り当てを使用するオブジェクトを渡しているため、ヒープ マネージャーを使用します。

上記1.の場合、 main() 関数はcout、ライブラリが見つからない場合にのみ単純な処理を行います。ただし、関数は終了する代わりにmain、ライブラリが見つかったかのように処理を続行します。

上記の場合、パラメーターとして DLL 関数に2.渡すとエラーが発生しやすく、何をしているのかを正確に理解していない限りお勧めしません。エラーが発生しやすい理由は、std::string

  • 関数呼び出しを含む DLL は、関数を呼び出す DLL とは異なるオプション セットでビルドされている可能性があります。これらの異なるオプションにより、std::string実装方法、メモリ内でのレイアウト方法などに 違いが生じる可能性があります。

  • 関数呼び出しを含む DLL は、関数を呼び出す DLL とは異なるバージョンのコンパイラによってビルドされている可能性があります。繰り返しますが、異なる実装による同じ問題std::string

  • std::string を使用する DLL およびモジュールDLL versionは、C ランタイム ライブラリを使用してビルドされていない可能性があります。DLL/モジュールがランタイム ライブラリの DLL バージョンを使用してビルドおよびリンクされていない場合、DLL はモジュールとは異なるヒープを使用します。使用されているメモリ ヒープが異なるため、std::string に対する操作はすべて無効になります。

つまり、一言で言えば、それを保証できない限り、

  1. まったく同じバージョンのコンパイラとコンパイラ オプションを使用して、モジュールと DLL をビルドしています。
  2. すべてのモジュールをランタイム ライブラリの DLL バージョンにリンクしています。

次にstd::string、パラメーターとして渡します。一般に、動的に割り当てられたメモリを保持するオブジェクトを渡すと、実行時エラーが発生する可能性があります。

于 2014-07-28T16:45:14.577 に答える
1

不十分なエラー処理とモジュール境界を越えた標準ライブラリの使用に加えて、考慮すべきことが他に 2 つあります。

dll で SetDllDirectory を使用して ... を実行できますか?

はい、できますが、すべきではありません。(発生するのを待っているバグ)。

なんで ?環境の変化を担当する唯一のエンティティはメインアプリケーションであるためです。ライブラリ コード (静的または dll) は、それがどのアプリケーションで使用されるかを知りません。一部のプログラムでは正しく動作する場合もあれば、他のプログラムでは失敗する場合もあります。

dll で C++ LoadLibrary/FreeLibrary を使用して ... を実行できますか?

はい、できますが、プログラムをデッドロックする可能性があるため、dllmain 関数では使用しないでください。

于 2014-07-28T17:03:21.280 に答える