
DLL関数を使ったプログラムを動かしたんですが、ERRORが解決できず
困っています。DLLを作成したのはいいのですが、それをLoadLibraryで読み込もうとしても指定したプロシージャが見つからないというエラーになるようです。使用している環境はVisual Studio.NET2003です。
以下はDLLのソースです。
// plug.c //
#include <windows.h>
#include <stdio.h>
__declspec(dllexport) void CALLBACK TestFunc()
{
printf("DLLのTestFunc()関数が実行されました。\n");
}
これをビルドするとplug.dllとplug.expとplug.libが作成されました。
そしてこれを使用したプログラムが
// stab.c //
#include <windows.h>
#include <stdio.h>
typedef void (*TestFunc)(void);
void main()
{
HMODULE hModule;
DWORD error;
TestFunc funcPointer;
hModule = LoadLibrary(TEXT("plug"));
error = GetLastError();//error値が127
funcPointer = (TestFunc)GetProcAddress(hModule,TEXT("TestFunc"));
funcPointer();
FreeLibrary(hModule);
getchar();
}
LoadLibrary関数を使用してアプリのメモリ空間にDLLを読み込もうとしているんですが、ここでハンドルが正確に渡されていないみたいなんです。どうしてこうなるのか分かりません。わかる方いらっしゃったらよろしくお願いします。
No.7ベストアンサー
- 回答日時:
このようなBBSで聞かれるよりは、
MSDNをご自分で調べられた方が遥かに
自分のためになると思いますが。。。
まず、モジュール名ですが、
LoadLibraryは第1パラメータでファイル名の拡張子を省略した場合、
既定の拡張子として「.DLL」が追加されます。
実行モジュールの取得に失敗した場合、
拡張エラー番号は126になります。
まずは今回の127というエラーが本当にLoadLibraryの後直ぐに
取得された拡張エラーなのかを教えてください。
#GetLastErrorは直前に実行した関数のエラーしか見れないので、
#タイミング的に書き換わっている可能性があります。
エラー的に127が返されたということは、
GetProcAddressのエラーである可能性が非常に高いです。
もしもGetProcAddress関数のエラーで返されたエラーならば、
DLL側がdefファイルを使用してビルドされていない可能性があります。
DEFファイルを使用しない場合、VC++はエクスポートする関数名を
修飾するためDLL側で用意した関数の関数名を指定するだけでは
アドレスを取得できません。
取得側はGetProcAddressに"_TestFunc@0"というような
修飾された「完全に明確な名前」を指定する必要があります。
#修飾子名はビルドするたびに異なる可能性があります。
これを回避する為の一番手っ取り早い方法は、
plug.defというファイルをプロジェクトに取り込み、
エクスポートする関数名を限定する方法があります。
--- plug.def -------------------------------
LIBRARY plug
EXPORTS
TestFunc @1
---ここまで----------------------------------
参考URL:http://msdn.microsoft.com/ja-jp/library/cc429241 …
この回答への補足
plug.def(モジュール定義)をプロジェクトに取り込んでTestFuncで実行したところERRORなく動作しました。defファイルを取り込んだお陰ですね。ありがとうございます。
しかし、GetLastError()で値を見てみると、値が127のままです。
何故こうなるのかはとても気になるのですが、一応は普通に動いています。
No.17
- 回答日時:
> しかし、GetLastError()で値を見てみると、値が127のままです。
>何故こうなるのかはとても気になるのですが、一応は普通に動いています。
GetLastErrorですが、これは直前の「エラー」に関しての取得です。
つまり、関数に成功した場合に0が返ってくることにはなっていないのです。
http://msdn.microsoft.com/ja-jp/library/cc428944 …
非常にわかりずらいのですが、特定の関数以外の関数は、成功した時にはSetLastErrorは呼ばないのです。ということは、それ以前の関数呼び出しでのエラーの値がそのまま残っているということです。
なので、GetLastErrorを見る前に、関数が成功したかどうかの判定をする必要があるのです。
No.16
- 回答日時:
> 解決策として『extern "C"』をつけることです。
No13でも書きましたが、
Cリンゲージで修飾子抑制が有効なのは
あくまでも呼び出し規約が、
デフォルトの「__cdecl」の場合です。
呼び出し規約が__stdcallなどの場合、
Cリンゲージ指定であったとしても、
エクスポート名は始まりに「_」、
終わりに「@パラメータバイト数」
というCの修飾が行われます。
今回に限ってはNo11さんが言っている通り、
DEFファイルを使用する以外にないと思います。
No.15
- 回答日時:
この回答への補足
参考URLありがとうございます。DLLに関しては、まだ勉強不足という事もあってか初歩的なことも分からないです。ただ、皆さんのお陰で解決しつつあるわけですし、そろそろこの問題を締め切ろうと思います。
補足日時:2008/12/03 11:19No.14
- 回答日時:
★アドバイス
・『plug.c』をC言語としてコンパイルするか、
C++としてコンパイルして DLL を作成するかで関数名が異なります。
C++ではオーバーロードという機能があるため関数名の末尾などに
勝手に一意の文字列が追加されます。
ネットで『マングリング』を検索するといろいろと情報が出てきます。
http://eternalwindows.jp/windevelop/dll/dll06.html
・解決策として『extern "C"』をつけることです。
DLLソースと使う側のソースでC言語か、C++かを統一させます。
矛盾があると『マングリング』によって見つかりません。注意。
// plug.c
#include <stdio.h>
#include <windows.h>
extern "C" __declspec(dllexport) void TestFunc()
{
printf("DLLのTestFunc()関数が実行されました。\n");
}
// stab.c
#include <stdio.h>
#include <windows.h>
extern "C"{
typedef void (*TestFunc)(void);
}
参考URL:http://eternalwindows.jp/windevelop/dll/dll06.html
この回答への補足
リンケージ指定をやろうとすると、エラーになります。
エラーは( errorC2059:構文エラー:'文字列' )です。
cファイルで記述しているからエラーがでるんじゃないかと思うのですが。
No.13
- 回答日時:
> VC++ではリンケージ指定ではエクスポート名が装飾されるのを
> 避けることは出来ません関数名のままエクスポートできるのは
> defファイルのみです、それ以外の方法はありません
呼び出し規約を変更するすることで、
defファイルを使用しなくても、
修飾子名をはずすことができる場合があります。
>No10さんのC関数名の修飾をはずす方法か、
と書きましたが、今回の質問者さんは 呼び出し規約を
CALLBACK としているのでデフォルトだと__stdcallの呼び出しと
なるのでdefファイルでしかエクスポートできないかもしれません。
ためしに、__stdcallでCリンゲージ指定を行うと、
エクスポート名は「_TestFunc@0」となりました。
ちなみにデフォルトの__cdeclの呼び出し規約では
エクスポート名は「TestFunc」となりました。
No.12
- 回答日時:
>その方法を試したところERRORが起きました。
起こったことはともかくどういう内容だったかが重要では?
リンゲージの差異によるエラーだと思うので、
No10さんのC関数名の修飾をはずす方法か、
DEFファイルを使用することで解決できると思います。
DEFファイルやC関数名修飾については以下を参照。
http://msdn.microsoft.com/ja-jp/library/d91k01sh …
No.11
- 回答日時:
VC++ではリンケージ指定ではエクスポート名が装飾されるのを避けることは出来ません
関数名のままエクスポートできるのはdefファイルのみです、それ以外の方法はありません
# 装飾名の所為で取得できてないのは最初から確定してるからLoadLibraryの事はもう考えるな
参考URL:http://msdn.microsoft.com/ja-jp/library/56h2zst2 …
No.10
- 回答日時:
> その方法を試したところERRORが起きました。
> cファイルだったからだと思うのですが。リンケージ指定はC++だと出来るんですけどね。
extern "C"{
__declspec(dllexport) void __cdecl TestFunc(void);
}
__declspec(dllexport) void __cdecl TestFunc(void)
{
printf("DLLのTestFunc()関数が実行されました。\n");
}
typedef void __cdecl (*TestFunc)(void);
だと、どうでしょうか?
No.9
- 回答日時:
>フルパスにしても同じことが起こりました。
>あと、hModuleに入った値ですが0x10000000です。
そのときGetLastError()の値は0 (この操作は正しく終了しました。)になっていたはずです。
LoadLibrary()が成功すればGetLastErrorは0になります。
パスの指定も原因のひとつだったという事が考えられます。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
python エラー
-
IOCTL_CDROM_RAW_RAEDで生デー...
-
DLL関数を使ったプログラム
-
エクセルのエラーメッセージ「4...
-
Excelのエラーで困ってます。
-
VBAでファイルを開くプログラム...
-
ビルド失敗 指定されたファイ...
-
ASP.NETの実行時のエラーについて
-
VC++6.0 の/Zm オプションについて
-
FileUploadを利用しての画像保...
-
VisualStudio2010 VC++ エラー
-
VC6からVS2005への移行エラーに...
-
ccコマンド時の0711-317エラー
-
新版 明解 C++ 入門編 につ...
-
C++でscanfは使えない?
-
構文エラーについて
-
PC画面を録画するプログラムでd...
-
右オペランドを扱う演算子は定...
-
ハンドルされていない例外…
-
BC30002: 型 'ListItem' が定義...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
python エラー
-
エクセルのエラーメッセージ「4...
-
Excelのエラーで困ってます。
-
適切な変換関数が存在しない???
-
fortranでプログラムを実行する...
-
コンパイルできません。
-
ビルド失敗 指定されたファイ...
-
VB2008で定数に色の設定をした...
-
バッチからsqlplusの接続エラー...
-
HEWを使用しているのですが、こ...
-
デバッグ中のエラーのことで教...
-
visual C++ でビルドの中止がで...
-
DLL関数を使ったプログラム
-
Arduinoに関する質問
-
sys/time.hのインクルードがで...
-
Visual Studioのstrcpy_sについて
-
BC30002: 型 'ListItem' が定義...
-
RightとLeft関数のライブ...
-
VBAでファイルを開くプログラム...
-
HANDLEの宣言でのエラー
おすすめ情報