1

C++ dll を動的にロードしようとしました。最初に「LoadLibrary」関数を使用して dll をロードし、ハンドルを正しく取得しています。その後、「GetProcAddress」を使用してDLLファイル関数の関数ポインタを取得しようとしましたが、NULLを返しています。私の DLL コードとテスト アプリケーション コードを見つけて、コードのどこが間違っているか教えてください。

ダミー2.h

namespace newer
{
  class dllclass
  {
    public:
        static __declspec(dllexport) int run(int a,int b);
  };
}

ダミー2.cpp

#include <iostream>
using namespace std;

#include "dummy2.h"

namespace newer
{
  int dllclass::run(int a,int b)
  {
    return a+b;
  }
}

ダミー1.cpp

#include "stdafx.h" 
#include <windows.h>

#include <iostream>
using namespace std;
typedef int (*Addition)(int,int);

int _tmain(int argc, _TCHAR* argv[])
{
  Addition add;
  HINSTANCE hDLL;
  hDLL = LoadLibrary(TEXT("Dummy2.dll"));

  add = (Addition)GetProcAddress(hDLL, "run");  

  getchar();
  return 0;
}

上記のコードを参照して、私を導いてください。

4

2 に答える 2

6

これは、名前が壊れているためです (つまり、関数の名前が「run」ではなく、別の名前になっている)。

あなたのコードは(私がテストしたMSVC 2013の場合)で動作します:

add = (Addition)GetProcAddress(hDLL, "?run@dllclass@newer@@SAHHH@Z");
cout << add(1, 2) << endl;

一般に、プラグインを介してクラスをロードする場合、最善の方法はvirtual interfaceを使用することです。例:

//dummy2.h
namespace newer
{
  class dllclass_interface
  {
    public:
        virtual int run(int a,int b) = 0;
 };

}

extern "C" __declspec(dllexport) newer::dllclass_interface* getDllClass();

//dummy2.cpp
#include <iostream>
using namespace std;

#include "dummy2.h"

namespace newer
{
  class dllclass: public dllclass_interface
  {
    public:
        virtual int run(int a,int b);
 };

  int dllclass::run(int a,int b)
  {
    return a+b;
  }
}

extern "C" newer::dllclass_interface* getDllClass()
{
    static newer::dllclass instance;
    return &instance;
}

typedef newer::dllclass_interface* (*GetClassFunc)();

GetClassFunc getClassFunc = (GetClassFunc)GetProcAddress(hDLL, "getDllClass");

newer::dllclass_interface* dllClass = getClassFunc();
cout << dllClass->run(a, b) << endl;
于 2017-01-04T10:14:35.950 に答える
1

実際、DLL は C の時代に導入されました。それ以来、C++ は関数名のオーバーロード (パラメーターの型に応じて) と「マングル名」と呼ばれるものを導入して、関数呼び出しを適切な名前にリンクできるようにしました。C++ 標準では、この名前がどのように表示されるかを指定していません。コンパイラが異なれば、パラメータの型を名前に埋め込む方法も異なります。

C++ はこの問題を理解しており、予測可能な名前が必要になる場合があります。そのために、C++ には特別な構文があります。

extern "C"
{
     int run(int, int);
}

関数の名前を指定するときはGetProcAddress、DLL からエクスポートされたものとまったく同じでなければなりません。これらの名前は、 DependencyWalkerなどの特別なユーティリティを使用して表示できます。

于 2017-01-04T10:10:31.887 に答える