• ベストアンサー

GetProcAddressとUnicode、Ansiについて

先日似たような部分で疑問が生じましたが GetProcAddressについて、実践的な部分をもうちょっと詳しく知りたくなりました。 Unicode版、Ansi版での、ロードする関数名が 末尾にWかAがついてることが多いと思うのですが GetProcAddressには文字列を指定しなければならないため なるべく手間を避けるとしても #ifdef _UNICODE #define _FWA(x) #x"W" #define _tfuncwa(x) L#x L"W" #else #define _FWA(x) #x"A" #define _tfuncwa(x) #x"A" #endif こういう風にプリプロセッサに対してなんらかの配慮をして置いたうえで HMODULE hDLL( LoadLibrary(_T("Shlwapi.dll")) ); typedef HRESULT (__stdcall *Func)( LPCTSTR ); Func func = (Func)GetProcAddress(hDLL,_FWA(PathFileExists)); とかやるようにするか、若しくはDllから動的に引っ張ってくる関数の周りで使う文字列は UnicodeかAnsiかに決め打ちして、必要が生じるなら変換、といった配慮のいずれかは必ず必要になるのでしょうか?

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

  • ベストアンサー
  • reset_cat
  • ベストアンサー率68% (94/138)
回答No.2

以下の2種類の方法を検討しているのでしょうか? 1.ANSI文字列を受け取る関数とUnicode文字列を受け取る関数の両方をDLLに実装し、マクロで関数名を変換する 2.関数呼び出しの前後で、文字列の型が合わない場合は文字列変換処理を入れる Cの場合は上記のような方法で変換を行うことになると思います。 C++の場合、オーバーロード機能によって同じ関数名でも引数の型を別々のものにすることで、上記のような変換を行う必要はなくなるかと思います。 で、GetProcAddress関数ですが、この関数はちょっと特殊で、文字列の引数があるにもかかわらずANSI文字列を受け取る関数形式しかありません。(後ろにAとかWが付かない) なので、定数で書く場合は_Tマクロなど、Unicode定義は必要ありません。 また、変数で渡す場合はchar型で渡す必要があるため、wchar_t型になっている場合はあらかじめ文字列をchar型に変換しておく必要があります。

LongSecret
質問者

お礼

ありがとうございます。 自分でC++で作るとか、C++で作られたライブラリなら、しっかりしたやつならだいたい両方対応している可能性が高いはずなのでその手でおkだと思いますが WindowsAPIとかをこういう風に呼び出すなら、やはりこうするのがいいのでしょうかね? GetProcAddressそのものにはANSIしかない、ということは大丈夫です。これを使うのはおそらく手打ちですからね。 これに渡す文字が_Tで囲まれてると、マルチバイトでしかコンパイルできなくなるはずですねw 実際には上記マクロはこの場合 #ifdef _UNICODE #define _FWA(x) #x"W" #else #define _FWA(x) #x"A" #endif だけあれば十分かと思います。 _tfuncwa(x) は、出力してマクロが正常に機能するかチェックしたときに作った、おまけですw、 上記コードの場合なら 呼び出すことになる PathFileExistsA か PathFileExistsW に対しては、設定によってどちらでも対応できるように TCHARを使っておけばいい、ということになるはずです。 やはり よほどのことがない限り、そういうことなら文字列変換はわざわざやらないようにする方が良いですよね?

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (1)

  • gentoo314
  • ベストアンサー率41% (15/36)
回答No.1

回答にはなっていませんが、DLLの遅延ロード機能を使用するとその辺の事は意識しなくて済むと思います。

LongSecret
質問者

お礼

ありがとうとございます♪ 遅延ロード機能というのは、具体的にはどうやって実現するもののことなのでしょうか?

LongSecret
質問者

補足

(事後) ある程度の見当はついたかも、という感じなので、時間ができたらじっくり調べてみることにします。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 最適化オプションと 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(); 直後に落ちてしまいます。 また、別のプロジェクトでも、最適化オプションなしなら正常に動くのですが、最適化オプションを付けると、そちらは初期化関数サイドを抜ける瞬間には落ちてしまいます。 アセンブリ出力を見ても、関数名とかはそのまま書かれている分に感じるので、どこがまずいのかよく分かりません。 これらはどのように対処すればいいのでしょうか? あるいは、書き方自体が間違っている(未定義動作になる)部分があるのでしょうか?

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

  • 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; } *********************************************** 以上

  • PHPにおいて16進数のアスキー文字とユニコード

    文字列の明確な違いがわかりません。 たとえば16進数のアスキー文字であれば print "\x41"; とした場合  A という文字が出力されます。 また print 0x41; とした場合はアスキー文字ではなく 65という10進数における数値が出力されますね。 さらには print "\xe6\x96\x87\xe5\xad\x97\xe5\x88\x97"; と記述すると 文字列 という文字が出力されます。 ではそうではなくユニコード文字列というのはなんなのでしょうか? 一般てきに \u0000 という形式で表記される物ですが、コレがいまいちわかりません。 これは16進数のアスキー文字によるマルチバイト文字の再現と何がことなるのでしょうか? たとえば、JSONなんかを単純に出力してみるとこのユニコード文字列という形式で表現されますよね? このユニコード文字列の実態?を知りたいです。 よろしく御願いします。

    • ベストアンサー
    • PHP
  • C言語での関数形式マクロの使い方

    前の質問No.300834(関数形式マクロと空白の質問)と関連します。 関数形式マクロで、引数として入れるものは、変数でなくて型名でも構わないのでしょうか。 例えば、 #define mymul(t,x,y) ((t)(x)*(t)(y)) と定義すると、 mymul(int, 5.0, 3.5) と呼び出すと、 ((int)(5.0)*(int)(3.5)) に置き換える、 (intでキャストした 5.0 と、intでキャストした 3.5 をかける) というのは可能でしょうか。 あと、関数形式マクロの呼び出しは、実行部分でなくてもよいのでしょうか。関数頭部(関数の本体の前の部分)で呼び出せますか。 例えば #define ARGUMENT3(t1,v1,t2,v2,t3,v3) ¥ (t1 v1, t2 v2, t3 v3) #define a_func b_func ARGUMENT3 と定義しておいて、 関数を定義するときに、 int a_func(int,x, char*,cp, int**,ypp) { ・・・・ } こんなことをすると、 int b_func(int x, char *cp, int **ypp) { ・・・・ } に置き換わりますか? もし、ARGUMENT3の定義を、ARGUMENT3の後の括弧の中のカンマのつけ方を変えて、 #define ARGUMENT3(t1 v1,t2 v2,t3 v3) ¥ (t1 v1, t2 v2, t3 v3) とし、 int a_func(int x, char* cp, int** ypp) { ・・・・ } こうすると、先ほどのようなb_funcの関数頭部に変換することは出来ませんか? (関数形式マクロでこのような空白の入れ方をしてよいのでしょうか。)

  • EXE1→DLL→EXE2数値を受け渡す方法

    C++プログラムの初級者です。 EXE1の数値をDLLの関数Func1に渡し、そこで計算した結果を関数Func2でEXE2に送るプログラムを作成しています。 下記のようなDLLのコードを作成したのですが、うまく数値を受け渡すことが出来ません。 調べてみると、EXE1⇔DLLとEXE2⇔DLLとは、アドレス空間が別なので、DLLのStatic変数を共有できないようです。 EXE1⇔DLL と EXE2⇔DLL の1対1では数値受け渡しは、正常に動作しています。 具体的に、DLLにどのようなコードを書けば、数値を受け渡すことができるのでしょうか? ご指導よろしくお願いします。 VC++2010ExpressEdition で作成しています。 <DLLのソースコード> ---------------------- #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <stdlib.h> #include <stdio.h> #include <iostream> static double aa, bb; __declspec(dllexport) double __stdcall Func1(double a1, double b1) { aa = a1*2; return (double)(aa); } __declspec(dllexport) double __stdcall Func2(double a2, double b2) { return (double)(aa); } BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) { //---- switch(ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } //---- return(TRUE); }

  • bcc32 GetProcAddress( )

    mydll.cpp と mymain.cpp でDLL内の関数を使うテストを しようとしたところです。 GetProcAddress( ) が失敗します。 どこを直せばいいか教えてください。 ///////// mydll.cpp #include <windows.h> extern "C" __declspec(dllexport) int MyFunc(int, int); int MyFunc(int a, int b){return( a + b );} ///////// mymain.cpp #include <windows.h> typedef int (*FUNCTYPE)(int, int); LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){  HMODULE hModule;  FUNCTYPE ft;  int i;  switch(msg){  case WM_RBUTTONDOWN:   hModule = LoadLibrary("mydll.dll");   ft = (FUNCTYPE)GetProcAddress(hModule, "MyFunc");   if(ft == NULL){    //GetLastError();   }   i = (*ft)(7, 8);  break;  case WM_DESTROY:   PostQuitMessage(0);  break;  default:   return DefWindowProc(hWnd, msg, wParam, lParam);  }  return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int){  ・・・ } ///////// コンパイル C:\bcc32 -WD mydll C:\bcc32 -W mymain mydll.obj ///////// 実行 LoadLibrary( ) は NULL 以外を返しました。 DLL_PROCESS_ATTACH は確認できました。 GetProcAddress( ) は NULL を返しました。

  • fgetws関数で読み込んだUNICODE文字列の文字化け

    お世話になります。 UNICODE文字列について上手くいかない部分があったので質問します。 (1)ANSI文字コードのテキストファイルをfgetws関数で読み込む (2)読み込んだ文字列をID3DXFont::DrawTextWメソッドで描画 以上のことを行うと、1バイト文字(半角文字)はきちんと表示されるのに対し、2バイト文字は化けてしまいます。 きちんと表示されるようにするにはどうすれば良いでしょうか? 開発環境:Visual Studio 2005 C++ 開発言語:C/C++(Win32API)+DirectX9.0b ご存知の方がいましたら、よろしくお願いします。

  • VBで、関数を関数の引数にするは?

    VBで関数の引数に、関数を呼ぶにはどのようにすればいいでしょうか?  例えば以下のようなイメージです   DEF FUNC1(X)=X^2   DEF FUNC2(F,a,b)=F(a)+F(b)     関数FUNC2では、関数Fを引数にする     つまりFUNC2(FUNC1,1,2)は     FUNC1(1)+FUNC1(2)=1^2+2^2=5 こんな感じです。 お教えください。

  • 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"不正な入力"; } } } }