C アプリから C++ DLL の変数にアクセスできない
-
09-06-2019 - |
質問
従来の Visual C++ 6 アプリの修正で行き詰まっています。私が置いたC++ DLLソースには
extern "C" _declspec(dllexport) char* MyNewVariable = 0;
その結果、MyNewVariable がエクスポート テーブルに (美しく装飾されていない) 表示されます (dumpbin /exports blah.dll で示されているように)。ただし、C ソース ファイルで変数にアクセスできるように変数を宣言する方法がわかりません。さまざまなことを試してみましたが、
_declspec(dllimport) char* MyNewVariable;
しかし、それは私にリンカーエラーを与えるだけです:
未解決の外部シンボル "__declspec(dllimport) char * MyNewVariable" (__imp_?MyNewVariable@@3PADA)
extern "C" _declspec(dllimport) char* MyNewVariable;
Tony が提案したように (そして私が以前に試したように) 予想される装飾とは異なる結果になりますが、まだ削除されていません。
未解決の外部シンボル __imp__MyNewVariable
C++ DLL 変数に C アプリからアクセスできるように宣言を記述するにはどうすればよいですか?
答え
botismarius や他の人が指摘したように (皆さんに感謝します)、DLL の .lib にリンクする必要がありました。名前が壊れるのを防ぐために、デコレータを使用せずに (C ソース内で) 名前を宣言する必要がありました。つまり、.lib ファイルを使用する必要がありました。
解決
DLL のコンパイル後に生成されたライブラリに対してリンクする必要があります。プロジェクトのリンカー オプションに、 .lib
ファイル。そして、はい、変数を次のように宣言する必要もあります。
extern "C" { declspec(dllimport) char MyNewVariable; }
他のヒント
extern "C" は装飾を削除する方法です。次のように使用すると機能するはずです。
extern "C" declspec(dllimport) char MyNewVariable;
または、C++ または C (/TC スイッチ付き) で使用できるヘッダーが必要な場合
#ifdef __cplusplus
extern "C" {
#endif
declspec(dllimport) char MyNewVariable;
#ifdef __cplusplus
}
#endif
そしてもちろん、エクスポートを実行する DLL によって生成されたインポート ライブラリとリンクします。
誰が botismarius をダウンモッドしたのかは分かりませんが、彼の言うことは正しいからです。その理由は、生成される .lib は、外部変数/関数を簡単に宣言できるインポート ライブラリであるためです。 __declspec(dllimport)
そしてそれを使うだけです。インポート ライブラリは必要な作業を単純に自動化します。 LoadLibrary()
そして GetProcAddress()
呼び出します。これがない場合は、これらを手動で呼び出す必要があります。
どちらも正しいです。エラーメッセージに記載されている事実 __imp_?MyNewVariable@@3PADA
は装飾された名前を探していることを意味するため、extern "C" が必要です。ただし、インポートライブラリとのリンクは また 必要でない場合は、別のリンク エラーが発生するだけです。
@グレアム:それも正しいです。OPが使用している「C」コンパイラはC99標準を強制しているのではなく、C++としてコンパイルしているため、名前が壊れていると思います。本物の C コンパイラは、 extern "C"
キーワード。
の中に DLLのソースコード .lib ファイルが 輸出 象徴:
extern "C" _declspec(dllexport) char* MyNewVariable = 0;
C クライアントは、 ヘッダ この宣言を使用すると、クライアントコードは 輸入 象徴:
extern "C" _declspec(dllimport) char* MyNewVariable;
このヘッダーは、DLL ソース コードで #include が指定されている場合にコンパイル エラーを引き起こすため、通常は、エクスポートされた関数に対してのみ、またクライアントによってのみ使用されるエクスポート ヘッダーに配置されます。
必要に応じて、次のようなどこにでも含めることができる「ユニバーサル」ヘッダーを作成することもできます。
#ifdef __cplusplus
extern "C" {
#endif
#ifdef dll_source_file
#define EXPORTED declspec(dllexport)
#else
#define EXPORTED declspec(dllimport)
#endif dll_source_file
#ifdef __cplusplus
}
#endif
EXPORTED char* MyNewVariable;
DLL のソース コードは次のようになります。
#define dll_source_code
#include "universal_header.h"
EXPORTED char* MyNewVariable = 0;
そしてクライアントは次のようになります。
#include "universal_header.h"
...
MyNewVariable = "Hello, world";
これを頻繁に行うと、先頭のモンスター #ifdef が import_magic.h に挿入され、universal_header.h は次のようになります。
#include "export_magic.h"
EXPORTED char *MyNewVariable;
Windows でプログラミングしていたときは、_declspec(dllimport) を使用したことがありませんでした。単純に宣言できるはずです
extern "C" char* MyNewVariable;
DLL のコンパイル時に作成された .libb へのリンク。