Visual C++でDLLを作ってC++Builderで読み込む(動的に読み込み)


表題の通り、VC++でDLL作ってC++Builderで読み込ませる、出来るだけシンプルな方法のメモ。

Visual C++側

新規作成->プロジェクト

テンプレート->Visual C++->空のプロジェクト

プロジェクト->[プロジェクト名]のプロパティ

構成プロパティ->全般->プロジェクトの既定値->構成の種類
を[ダイナミック ライブラリ (.dll)]に変更

クラスを追加

TestClass.h
class TestClass
{
public:
    TestClass();
    ~TestClass();
    int Data();
};

///C++ではなくCとして関数を作って、内部でクラスの処理を作っておく。
/// extern "C" __declspec(dllexport) 返り値 __stdcall 関数名(引数) {
/// ※__stdcallは入れておくこと。
extern "C" __declspec(dllexport) int __stdcall GetClassInstance() {
    int val;
    TestClass *test = new TestClass();
    val = test->Data();
    delete test;
    return val;
}
TestClass.cpp
#include "TestClass.h"
TestClass::TestClass()
{
}
TestClass::~TestClass()
{
}
int TestClass::Data(){
    return 255;
}

ビルド->ソリューションのビルドで出力

C++ Builder

適当にプロジェクトを作って、
プロジェクト -> オプション
ビルドイベント -> ビルド前イベント -> コマンド

TestDll.dllという名前の場合
copy /y "[VC++DLLの出力先]TestDll.dll" "$(OUTPUTDIR)TestDll.dll"

を追加して、C++Builderでビルド前にコピーをしてくる。

Unit.cpp
///出力にCodeSiteを使用。
void __fastcall Test(){
    HMODULE dll = LoadLibrary(L"TestDll.dll");///ファイル名
    if (dll == NULL) {
        CodeSite->Send("DLLの読み込みに失敗しました。");
        return;
    }
    typedef int (*TAddProc)();///typedef 返り値 (*関数ポインタ名)(引数);

///関数の名前はstdcallの場合
/// _関数名@引数のバイト数
///と入力する。
///分からなかったらDLLファイルをDependency Walkerというツールで読み込ませて調べられる
///http://www.dependencywalker.com
///https://msdn.microsoft.com/ja-jp/library/zxk0tw93.aspx
    FARPROC proc = GetProcAddress(dll, "_GetClassInstance@0");
    if (proc == NULL) {
        CodeSite->Send("関数のアドレスの取得に失敗しました。");
        return;
    }

    TAddProc hoge = reinterpret_cast<TAddProc>(proc);
    CodeSite->Send(hoge());
    FreeLibrary(dll);
}

参考
http://www.gesource.jp/programming/bcb/dll/03.html