• ベストアンサー

DLL関数を使ったプログラム

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

質問者が選んだベストアンサー

  • ベストアンサー
  • aris-wiz
  • ベストアンサー率38% (96/252)
回答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.aspx
dotneer
質問者

補足

plug.def(モジュール定義)をプロジェクトに取り込んでTestFuncで実行したところERRORなく動作しました。defファイルを取り込んだお陰ですね。ありがとうございます。 しかし、GetLastError()で値を見てみると、値が127のままです。 何故こうなるのかはとても気になるのですが、一応は普通に動いています。

その他の回答 (16)

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.17

> しかし、GetLastError()で値を見てみると、値が127のままです。 >何故こうなるのかはとても気になるのですが、一応は普通に動いています。 GetLastErrorですが、これは直前の「エラー」に関しての取得です。 つまり、関数に成功した場合に0が返ってくることにはなっていないのです。 http://msdn.microsoft.com/ja-jp/library/cc428944.aspx 非常にわかりずらいのですが、特定の関数以外の関数は、成功した時にはSetLastErrorは呼ばないのです。ということは、それ以前の関数呼び出しでのエラーの値がそのまま残っているということです。 なので、GetLastErrorを見る前に、関数が成功したかどうかの判定をする必要があるのです。

dotneer
質問者

補足

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

  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.16

> 解決策として『extern "C"』をつけることです。 No13でも書きましたが、 Cリンゲージで修飾子抑制が有効なのは あくまでも呼び出し規約が、 デフォルトの「__cdecl」の場合です。 呼び出し規約が__stdcallなどの場合、 Cリンゲージ指定であったとしても、 エクスポート名は始まりに「_」、 終わりに「@パラメータバイト数」 というCの修飾が行われます。 今回に限ってはNo11さんが言っている通り、 DEFファイルを使用する以外にないと思います。

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.15

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

参考URL:
http://www.interq.or.jp/www-user/wanderer/program/memo/lecture/compiler.html#linker
dotneer
質問者

補足

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

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.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
dotneer
質問者

補足

リンケージ指定をやろうとすると、エラーになります。 エラーは( errorC2059:構文エラー:'文字列' )です。 cファイルで記述しているからエラーがでるんじゃないかと思うのですが。

  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.13

> VC++ではリンケージ指定ではエクスポート名が装飾されるのを > 避けることは出来ません関数名のままエクスポートできるのは > defファイルのみです、それ以外の方法はありません 呼び出し規約を変更するすることで、 defファイルを使用しなくても、 修飾子名をはずすことができる場合があります。 >No10さんのC関数名の修飾をはずす方法か、 と書きましたが、今回の質問者さんは 呼び出し規約を CALLBACK としているのでデフォルトだと__stdcallの呼び出しと なるのでdefファイルでしかエクスポートできないかもしれません。 ためしに、__stdcallでCリンゲージ指定を行うと、 エクスポート名は「_TestFunc@0」となりました。 ちなみにデフォルトの__cdeclの呼び出し規約では エクスポート名は「TestFunc」となりました。

  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.12

>その方法を試したところERRORが起きました。 起こったことはともかくどういう内容だったかが重要では? リンゲージの差異によるエラーだと思うので、 No10さんのC関数名の修飾をはずす方法か、 DEFファイルを使用することで解決できると思います。 DEFファイルやC関数名修飾については以下を参照。 http://msdn.microsoft.com/ja-jp/library/d91k01sh.aspx

noname#208124
noname#208124
回答No.11

VC++ではリンケージ指定ではエクスポート名が装飾されるのを避けることは出来ません 関数名のままエクスポートできるのはdefファイルのみです、それ以外の方法はありません # 装飾名の所為で取得できてないのは最初から確定してるからLoadLibraryの事はもう考えるな

参考URL:
http://msdn.microsoft.com/ja-jp/library/56h2zst2.aspx
  • titokani
  • ベストアンサー率19% (341/1726)
回答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); だと、どうでしょうか?

  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.9

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

  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.8

> plug.defというファイルをプロジェクトに取り込み、 言葉足らずですね。 defファイルを取り込むのは「DLL側のプロジェクト」です。 DLLのリビルドが必要です。

関連するQ&A

  • DLLの関数呼び出しで引数があるとフリーズしてしまう。

    はじめまして、C言語勉強中の初心者です。 現在、DLLに定義されている関数を呼び出すことを試していますが、うまくいかないので質問させて頂きました。 DLLには2つの関数が定義されています。  1.void Hello()  2.void HelloEx(char *pval); 1の関数を呼び出す場合は異常なく終了するのですが、2の関数を呼び出すと、フリーズしてしまいます。 フリーズする原因が分からないので、教えて頂ければと思います。 以下にソースを掲載します。 因みにコンパイラはBCC5.5.1を使用しています。 ***************************************************** DLL(Hello.c) [bcc32 -WD Hello.c] ***************************************************** #include <windows.h> #include <stdio.h> __declspec(dllexport) void CALLBACK Hello(void) { printf("Hello!\n"); } __declspec(dllexport) void CALLBACK HelloEx(char *pVal) { printf("Hello!%s\n", pVal); } ***************************************************** EXE(HelloTest.c)[bcc32 -L HelloTest.c] ***************************************************** #include <windows.h> #include <stdio.h> typedef void (*Hello)(void); typedef void (*HelloEx)(char*); int main(void) { HMODULE hMod; Hello func; HelloEx funcEx; hMod = LoadLibrary( "Hello.dll" ); if(!hMod) return FALSE; func = (Hello)GetProcAddress( hMod, "Hello"); if(!func) return FALSE; funcEx = (HelloEx)GetProcAddress( hMod, "HelloEx"); if(!funcEx) return FALSE; func(); funcEx("World"); FreeLibrary(hMod); return 0; } *********************************************** 以上

  • DLLの明示的な読み込みの方法

    開発環境:WindowsXP sp2 + VisualStudio2005 MSDNやその他のWebページで、DLLの明示的なロードについて勉強しています。 試しに以下のようなコードを書いてみたのですが、コンパイルは通りますが、実行時にDLLが読み込まれているのにもかかわらず、関数のアドレスが取得できません。 ---DLLのコード--- #include <iostream> using namespace std; __declspec(dllexport) void printMessage() { cout<<"printMessage関数が呼ばれた"<<endl; } ---終わり--- コンパイルしたDLLのみをDLLを使用した実行形式がコンパイル後に収納されるフォルダに移動して、以下のコードを書いてコンパイルしました。 ---EXEのコード--- #include <windows.h> #include <iostream> typedef void(*TFUNC)(); int main(void) { HINSTANCE hInstDLL; TFUNC DllFunction; //DLLの読み込み hInstDLL=LoadLibrary(L"dll.dll"); if(hInstDLL==NULL) { std::cout<<"ERROR"<<std::endl; return 0; } //printMessage関数のアドレスを取得 DllFunction=(TFUNC)GetProcAddress(hInstDLL,"printMessage"); //この辺りがおかしいかも知れない //関数の使用 if(DllFunction==NULL) { std::cout<<"ERROR"<<std::endl; FreeLibrary(hInstDLL); return 0; } DllFunction(); //DLLの解放 if(!FreeLibrary(hInstDLL)) return 0; return 0; } ---終わり--- DLLは見つかる物の、どうも上手くいかないようです......原因は何なのでしょうか。

  • 最適化オプションと LoadLibrary(あるいはCoInitialize関連?)などを組み合わせると…

    コンパイラはVisual C++ 2008 Express Editionです。 以下のようなコードを書くと #include <windows.h> #include <stdio.h> #include <tchar.h> #include <commctrl.h> #pragma comment ( lib, "comctl32.lib") HRESULT InitCOM_Ole32(){ //初期化 HMODULE hDLL( LoadLibrary(_T("Ole32.dll")) ); if (!hDLL) return E_FAIL; typedef HRESULT (*Func)( LPVOID ); Func func = (Func)GetProcAddress(hDLL,"CoInitialize"); HRESULT hr( func( 0 ) ); FreeLibrary( hDLL ); return hr; } void UnInitCOM_Ole32(){ //後始末 HMODULE hDLL( LoadLibrary(_T("Ole32.dll")) ); if (!hDLL) return; void (*func)() = (void (*)())GetProcAddress(hDLL,"CoUninitialize"); func(); FreeLibrary( hDLL ); } int main(){ InitCOM_Ole32(); InitCommonControls(); UnInitCOM_Ole32(); getchar(); return 0; } 最適化オプションが無効なら問題ないのですが、最適化オプションを付けると getchar(); 直後に落ちてしまいます。 また、別のプロジェクトでも、最適化オプションなしなら正常に動くのですが、最適化オプションを付けると、そちらは初期化関数サイドを抜ける瞬間には落ちてしまいます。 アセンブリ出力を見ても、関数名とかはそのまま書かれている分に感じるので、どこがまずいのかよく分かりません。 これらはどのように対処すればいいのでしょうか? あるいは、書き方自体が間違っている(未定義動作になる)部分があるのでしょうか?

  • LoadLibraryの戻り値(HMODULE)について

    ファイル名の異なる2つのDLLを下記のソースの様 にLoadLibraryしたところA,Bとも同じアドレスが 戻って来てしまいます。これではFreeLibraryにて 開放しようとした時に、おかしな事になってしまう と思うのですが、なぜ同じアドレスが戻ってくるのか 分りません。 あと、A,Bをグローバル変数として宣言 したときに、既に宣言済みですと怒られます。これも よく分りません。何方か理由が分る方ご教授願います。 void CXXX_Dlg::ButtonClick() { // dllファイルロード HMODULE A = ::LoadLibrary("A.DLL"); HMODULE B = ::LoadLibrary("B.DLL"); } 環境:Win2K, VC++.Net 2003 MFC です。 DLLファイルはプロジェクトと同ディレクトリに 入っています。

  • VC++フォームアプリケーションにDLLをリンク2

    2日前に、同じタイトルで投稿した者です。 http://okwave.jp/qa/q7326569.html その節は素晴らしい回答を頂きありがとうございました。 それを実現するように、作成して頂いたプログラムの修正に取り組んでいるのですが、うまく行きません。 どなたかお力をお貸し下さいm(>o<)m 前回の回答で、指摘されたように、LoadLibrary/GetProcAddress/FreeLibrary を用いて 作成して頂いたプログラムを修正しました。 具体的には、ボタンを押すとSecretFunc関数を呼び出すコードForm1.cppを以下のように修正しました。ビルドしても、エラーは出ません。 次に、このプログラムのReleaseフォルダー内のDLL_sample.dllを 前回、私が投稿したソースコード(http://okwave.jp/qa/q7326569.html)で作成したDLL_sample.dllと置き換えました。 そして、プログラムを起動(WinForm_sample.exe)すると、エラーは発生しないのですが、SecretFunc関数が見つけられず、プログラムの"No DLL"表示の方を通ります。 その原因が分かりません。 プログラムは全て、VC++2010ExpressEditionで作成しています。 もし、お分かりの方がいらっしゃいましたら、ご教授のほどよろしくお願いします。 //修正したForm1.cppのコード #include "stdafx.h" #include "Form1.h" #include "DLL_sample.h" #include <Windows.h> typedef UINT (CALLBACK* LPFNDLLFUNC1)(DWORD,UINT); namespace WinForm_sample { System::Void Form1::btnCalc_Click(System::Object^ sender, System::EventArgs^ e) { System::Double a, b; if ( System::Double::TryParse(txtA->Text, a) && System::Double::TryParse(txtB->Text, b) ) { HINSTANCE hDLL; // Handle to DLL LPFNDLLFUNC1 lpfnDllFunc1; // Function pointer //DWORD dwParam1; //UINT uParam2, uReturnVal; hDLL = LoadLibrary(TEXT("DLL_sample.dll")); if (hDLL != NULL) { lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL,"SecretFunc"); if (!lpfnDllFunc1) { // call the function double c = SecretFunc(a,b); txtResult->Text = c.ToString(); // handle the error FreeLibrary(hDLL); //return SOME_ERROR_CODE; } else { // Initializes the variables to pass to the MessageBox.Show method. txtResult->Text = L"No DLL"; } } else { txtResult->Text = L"不正な入力"; } } } }

  • [VC++]ヘッダファイルからの関数コール

    Formのボタンクリックイベント(Form.h)から 別ファイル(.cpp)の関数をコールしたいのですがうまくいきません、 どのようにすればよいでしょうか?ご教授お願いします。 1> : error C2144: 構文エラー : 'void' は ')' によって先行されなければなりません。 1> : error C2059: 構文エラー : ')' //----- main1.h #include <stdio.h> #include "Form1.h" namespace A { void main1(); } //----- main1.cpp #include <stdio.h> #include "main1.h" using namespace A; void main1() { //処理 } //----- Form1.h #include <stdio.h> #include "main1.h" void main1(void); namespace A { public ref class Form1 : public System::Windows::Forms::Form { public: private: System::Void btn_Click(System::Object^ sender, System::EventArgs^ e) { //★クリックイベントからmain1の関数コールしたい main1(void); } }; }

  • 【VS2008 C++】2つのプロジェクト間で共通の関数を使いたい

    【VS2008 C++】2つのプロジェクト間で共通の関数を使いたい WindowsXP上で visual studio 2008 C++ express editionを 使用しています。 1つのソリューションに2つのプロジェクトをつくり、 その2つに共通の関数を使用させたいのですが、どのように 設定すればよいか教えて頂けませんでしょうか。 ソースの内容は以下のとおりです。 具体的には、mainB.cppでcommon.cppの関数を 呼び出したいです。 //common.cpp #include <stdio.h> void showCommon(){ printf("---common-----\n"); } //common.h #include<stdio.h> void showCommon(); //mainA.cpp #include<stdio.h> #include "common.h" void main(){ printf("---mainA-----\n"); showCommon(); } //mainB.cpp #include<stdio.h> #include "common.h" void main(){ printf("---mainB-----\n"); showCommon(); }

  • 漢字の読みを表示するプログラム

    漢字の読みを表示するプログラム C/C++で漢字の読みを取得したいです。 kakasiを利用してみましたが、以下のようなエラーになってしまいます。 エラー内容:実行時エラーで、「○○.exeは動作を停止しました。」となります。 OS:Vistaです。 環境変数はマニュアル通りに設定しました。 ソースはネット上のサンプルを参考に書きましたが、 LoadLibrary・GetProcAddressなどの関数の意味がmsdnを見ても解りませんでした。 (環境変数に設定しない場合の書き方なのかもしれないと思い、消してみましたが、 そうすると多数のコンパイルエラーになってしまいます。) まずは動かしてみたいのです。よろしくお願いいたします。 以下エラーが出るソースです。 #include <stdio.h> #include <stdlib.h> #include <windows.h> #include "libkakasi.h" void main(void){ HMODULE hKakasiDLL = LoadLibrary("C:\\kakasi\\bin"); int (__cdecl *kakasi_getopt_argv)(int, char**) = (int (__cdecl *)(int, char**))GetProcAddress( hKakasiDLL, "kakasi_getopt_argv" ); char* (__cdecl *kakasi_do)(const char*) = (char* (__cdecl *)(const char*))GetProcAddress( hKakasiDLL, "kakasi_do" ); int (__cdecl *kakasi_free)(char *p) = (int (__cdecl *)(char *p))GetProcAddress( hKakasiDLL, "kakasi_free" ); putenv( "ITAIJIDICTPATH=C:\\kakasi\\share\\kakasi\\itaijidict"); putenv( "KANWADICTPATH=C:\\kakasi\\share\\kakasi\\kanwadict"); char* argv[] = {"kakasi", "-JH","-kH"}; kakasi_getopt_argv(3,argv); char* hiragana = kakasi_do("漢字"); printf("%s\n", hiragana); kakasi_free(hiragana); FreeLibrary(hKakasiDLL); }

  • DLLとexeでのインクルードについて

    いつもお世話になっております。DLLでincludeしたものはexeでもincludeしなければならないのか疑問に思っています。 例えば、 DLL側である関数abc()内でWindowsMessage()を使用するために#include<windows.h>とインクルードした場合。 Exe側では関数abc()を使用するためにwindouw.hをインクルードしなければならないのでしょうか。 試してみた所、インクルードしなくてもうまくいったのですがたまたま何かしらでうまくいっていただけかもと不安に思ったので、一般的にはどうなのかと思い質問させていただきました。

  • C++/CLIで、アンマネージC++のDLLを使用する方法

    こんにちは。 C++/CLIのプログラムで、アンマネージC++のDLLを使用したいと考えています。 ネット上をいろいろ調べたのですが、具体的な手段がわかりません。 見よう見まねで以下のようにサンプルを作成したのですが、コンパイルすら通る状況になりません。 かなり基本的な問題がありそうで申し訳ないのですが、下記の問題点を教えていただけないでしょうか。 また、参考になりそうなサイトなどありましたら教えていただけると大変助かります。 ■アンマネージC++のDLL VC++6.0で、以下のように、単にデバッグ文字列を書き出すだけのDLL関数を作成しました。 (このDLLが使用できることは他のVC++6.0プロジェクトで確認済みです) /*-----Func.h-----*/ #ifndef __FUNC_H__ #define __FUNC_H__ AFX_EXT_CLASS void WINAPI ShowMessage(); #endif //__FUNC_H__ /*-----Func.cpp-----*/ #include "StdAfx.h" #include "Func.h" #include <stdio.h> void WINAPI ShowMessage() { CString str = "This is The Message from DLL Func!\n"; OutputDebugString(str); } ■C++/CLI でのDLL使用 Visual Studio2008にて、C++のCLRプロジェクトを作成して、以下のようにDLLを使用する準備を行いました。 1.ソリューションエクスプローラのヘッダフォルダに、Func.hを追加 2.プロジェクトのフォルダに、上記で作成したFuncのDLLとLIBファイルを置く。 3.プロジェクトの「プロパティ > C/C++ > プリプロセッサ > プリプロセッサの定義」に、"_AFXDLL"を追加 4.mainクラスのソースに以下を記述 /*----------*/ using namespace System; #include "Func.h" #using "ManagedDllApp.dll" int main() { ShowMessage(); return 0; } /*----------*/ この状態でコンパイルすると、 「エラー 3 error C2144: 構文エラー : 'void' は ';' によって先行されなければなりません。 d:\xxx\Func.h 4 Console 」等、Func.h周りで複数のエラーが出ます。 また、Func.hをインポートしないでコンパイルすると、 「エラー 3 fatal error C1113: #using が 'd:\xxx\manageddllapp.dll' で失敗しました。 」と、Dllでエラーが出ます。 よろしくお願いいたします。

専門家に質問してみよう