DLLのなかのC++のクラスを利用する方法を教えてください。

DLL、およびそのDLLを使用するEXE両方を開発しています。(WindowsXPでVisualC++6.0)

DLLにはクラスのインスタンスがあり、そのポインタを返す関数(A)だけをExportしています。
EXEでは、DLL(LoadLibrary APIを使用して動的に呼び出しています)の関数(A)から、クラスのインスタンスのポインタを取得して利用します。
DLLで使用しているクラスのヘッダをそのまま使用すると、Lnkerがエラーをだすので、EXE側では 「virtual メソッド名 =0;」として純粋仮想関数へと書き換えたヘッダを利用しています。
他は特にプラグマなどは指定していません。

上記の状態で、DLLから取得したインスタンスを利用すると変数の利用は問題なくできるのですが、メソッドを呼び出そうとすると例外が発生します。vTableを値をメモリダンプでみてみると全然違うアドレスがはいっている(なんか文字列のワークっぽい)のでメソッド呼び出し時に不正なアドレスを呼び出しているようです。

このような利用方法を行う場合、どのようにするのが正しいでしょうか?

回答の条件
  • 1人10回まで
  • 登録:2007/09/13 20:39:24
  • 終了:2007/09/20 17:11:14

ベストアンサー

id:flashrod No.2

flashrod回答回数31ベストアンサー獲得回数32007/09/14 22:02:12

ポイント40pt

>EXE側では 「virtual メソッド名 =0;」として純粋仮想関数へと書き換えたヘッダを

DLL側でもこの同じ書き換えたヘッダファイルを利用しないといけないのではないでしょうか。

  • 純粋仮想関数だけ定義した抽象クラスXを定義
  • DLL側ではXから派生したconcreteなクラスをnew
  • EXE側ではDLLの(A)からインスタンスをXとして取得

たぶん、OLE2のCOMみたいなことをしようとしておられるようなので、原理的には可能なはずだと思います。

#Windowsプログラミングはもう何年もしてないので外してる可能性大ですが。

id:fslasht

回答ありがとうございます。

DLL内でも実体のクラスも純粋仮想クラスから派生するようにしたところうまくいきました。

以下注意点のメモ

【注意点】

・純粋仮想クラスのコントラスタは普通作らない

・純粋仮想クラスのデストラクタは、純粋仮想メソッドにしない(=0はつけない)。また、空の実装をつけとく。

例)

virtual ~TestClass() {};

※これをわすれたら、vtableが1個づつづれて難儀しました。

・DLL内でインスタンスを持つ場合は、sharedセグメントに置く

例) dll.cppに追加

#pragma data_seg(".shared")

TestClass test;

#pragma data_seg()

例) dll.defに追加

SECTIONS

.shared READ WRITE SHARED

2007/09/20 17:09:12

その他の回答(2件)

id:KUROX No.1

KUROX回答回数3542ベストアンサー獲得回数1402007/09/13 21:20:51

id:fslasht

回答ありがとうございます。

このサイトを参考にやってみます。

でもこの方法だと、libファイルをつかって暗黙的にリンクするしかないんですよね。

明示的にリンクする方法はないでしょうか。

2007/09/13 21:43:14
id:flashrod No.2

flashrod回答回数31ベストアンサー獲得回数32007/09/14 22:02:12ここでベストアンサー

ポイント40pt

>EXE側では 「virtual メソッド名 =0;」として純粋仮想関数へと書き換えたヘッダを

DLL側でもこの同じ書き換えたヘッダファイルを利用しないといけないのではないでしょうか。

  • 純粋仮想関数だけ定義した抽象クラスXを定義
  • DLL側ではXから派生したconcreteなクラスをnew
  • EXE側ではDLLの(A)からインスタンスをXとして取得

たぶん、OLE2のCOMみたいなことをしようとしておられるようなので、原理的には可能なはずだと思います。

#Windowsプログラミングはもう何年もしてないので外してる可能性大ですが。

id:fslasht

回答ありがとうございます。

DLL内でも実体のクラスも純粋仮想クラスから派生するようにしたところうまくいきました。

以下注意点のメモ

【注意点】

・純粋仮想クラスのコントラスタは普通作らない

・純粋仮想クラスのデストラクタは、純粋仮想メソッドにしない(=0はつけない)。また、空の実装をつけとく。

例)

virtual ~TestClass() {};

※これをわすれたら、vtableが1個づつづれて難儀しました。

・DLL内でインスタンスを持つ場合は、sharedセグメントに置く

例) dll.cppに追加

#pragma data_seg(".shared")

TestClass test;

#pragma data_seg()

例) dll.defに追加

SECTIONS

.shared READ WRITE SHARED

2007/09/20 17:09:12
id:q_taro4 No.3

q_taro4回答回数83ベストアンサー獲得回数12007/09/15 00:04:27

id:fslasht

回答ありがとうございます。

リンク先のページ参考にさせていただきました。

2007/09/20 17:10:32
  • id:fslasht
    単純化したサンプル

    ● DLL

    【dll.h】
    class TestClass {
    public:
    int GetNumber();
    int m_nNumber;
    };

    TestClass* GetClass(); // ★この関数をExport

    【dll.cpp】
    TestClass::GetNumber() {
    return nNumber;
    }

    TestClass test;
    TestClass* GetClass() {
    return &test;
    }

    ● EXE側

    【exe.h】
    class TestClass {
    public:
    virtual int GetNumber() =0;
    int m_nNumber;
    };

    【exe.cpp】
    TestClass* test = GetNumber();
    int n1=test->m_nNumber; // OK
    int n2=test->GetNumber(); // 例外発生

  • id:cx20
    >> http://www2s.biglobe.ne.jp/~ragnarok/program/win32/class_of_cpp_in_dll.htm
    > でもこの方法だと、libファイルをつかって暗黙的にリンクするしかないんですよね。

    Dependency Walker 等で、関数のシンボル名を取得して、

    pfn = (DLLFUNC)GetProcAddress( hInstDLL, "?getExport@@YAHPAVExport@@XZ" );

    とかすれば、一応、動的にロード可能です。推奨はしませんが・・・。

    ■ Dependency Walker (depends.exe) Home Page
    http://www.dependencywalker.com/
  • id:flashrod
    この例だとDLL側のint GetNumber();はvtableに入ってないので「全然違うアドレスがはいっている」のではないでしょうか。
  • id:fslasht
    【exe.cpp】のサンプルが間違ってました。

    【誤】
    TestClass* test = GetNumber();
    int n1=test->m_nNumber; // OK
    int n2=test->GetNumber(); // 例外発生

    【正】
    TestClass* test = GetClass(); // ★修正
    int n1=test->m_nNumber; // OK
    int n2=test->GetNumber(); // 例外発生

    です

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません