アプリ版:「スタンプのみでお礼する」機能のリリースについて

 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を読み込もうとしているんですが、ここでハンドルが正確に渡されていないみたいなんです。どうしてこうなるのか分かりません。わかる方いらっしゃったらよろしくお願いします。

A 回答 (17件中1~10件)

このような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のままです。
何故こうなるのかはとても気になるのですが、一応は普通に動いています。

補足日時:2008/12/02 21:48
    • good
    • 0

> しかし、GetLastError()で値を見てみると、値が127のままです。


>何故こうなるのかはとても気になるのですが、一応は普通に動いています。

GetLastErrorですが、これは直前の「エラー」に関しての取得です。
つまり、関数に成功した場合に0が返ってくることにはなっていないのです。
http://msdn.microsoft.com/ja-jp/library/cc428944 …
非常にわかりずらいのですが、特定の関数以外の関数は、成功した時にはSetLastErrorは呼ばないのです。ということは、それ以前の関数呼び出しでのエラーの値がそのまま残っているということです。

なので、GetLastErrorを見る前に、関数が成功したかどうかの判定をする必要があるのです。

この回答への補足

なるほど。特定の関数以外の関数は、成功したときはSetLastErrorは呼ばないんですね。

補足日時:2008/12/03 11:07
    • good
    • 0

> 解決策として『extern "C"』をつけることです。


No13でも書きましたが、
Cリンゲージで修飾子抑制が有効なのは
あくまでも呼び出し規約が、
デフォルトの「__cdecl」の場合です。

呼び出し規約が__stdcallなどの場合、
Cリンゲージ指定であったとしても、
エクスポート名は始まりに「_」、
終わりに「@パラメータバイト数」
というCの修飾が行われます。

今回に限ってはNo11さんが言っている通り、
DEFファイルを使用する以外にないと思います。
    • good
    • 0

★追記。


・『参考URL』をどうぞ。
 ここにDLLの注意点が書かれています。

参考URL:http://www.interq.or.jp/www-user/wanderer/progra …

この回答への補足

 参考URLありがとうございます。DLLに関しては、まだ勉強不足という事もあってか初歩的なことも分からないです。ただ、皆さんのお陰で解決しつつあるわけですし、そろそろこの問題を締め切ろうと思います。

補足日時:2008/12/03 11:19
    • good
    • 0

★アドバイス


・『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ファイルで記述しているからエラーがでるんじゃないかと思うのですが。

補足日時:2008/12/02 22:09
    • good
    • 0

> VC++ではリンケージ指定ではエクスポート名が装飾されるのを


> 避けることは出来ません関数名のままエクスポートできるのは
> defファイルのみです、それ以外の方法はありません
呼び出し規約を変更するすることで、
defファイルを使用しなくても、
修飾子名をはずすことができる場合があります。

>No10さんのC関数名の修飾をはずす方法か、
と書きましたが、今回の質問者さんは 呼び出し規約を
CALLBACK としているのでデフォルトだと__stdcallの呼び出しと
なるのでdefファイルでしかエクスポートできないかもしれません。

ためしに、__stdcallでCリンゲージ指定を行うと、
エクスポート名は「_TestFunc@0」となりました。
ちなみにデフォルトの__cdeclの呼び出し規約では
エクスポート名は「TestFunc」となりました。
    • good
    • 0

>その方法を試したところERRORが起きました。


起こったことはともかくどういう内容だったかが重要では?

リンゲージの差異によるエラーだと思うので、
No10さんのC関数名の修飾をはずす方法か、
DEFファイルを使用することで解決できると思います。

DEFファイルやC関数名修飾については以下を参照。
http://msdn.microsoft.com/ja-jp/library/d91k01sh …
    • good
    • 0

VC++ではリンケージ指定ではエクスポート名が装飾されるのを避けることは出来ません


関数名のままエクスポートできるのはdefファイルのみです、それ以外の方法はありません

# 装飾名の所為で取得できてないのは最初から確定してるからLoadLibraryの事はもう考えるな

参考URL:http://msdn.microsoft.com/ja-jp/library/56h2zst2 …
    • good
    • 0

> その方法を試したところ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);

だと、どうでしょうか?
    • good
    • 0

>フルパスにしても同じことが起こりました。


>あと、hModuleに入った値ですが0x10000000です。
そのときGetLastError()の値は0 (この操作は正しく終了しました。)になっていたはずです。
LoadLibrary()が成功すればGetLastErrorは0になります。
パスの指定も原因のひとつだったという事が考えられます。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています