トップ回答者
関数ポインタをマネージドクラスでラップする方法 @ C++/CLI

質問
-
お世話になります。
OpenGL では、glext.h や wglext.h というヘッダの中で様々な関数が定義されているのですが、それらを使うには wglGetProcAddress という関数で DLL 内 から 関数ポインタ を取ってくる必要があります。
例えば以下のクラスでは、Create という初期化関数を実行することで、wglChoosePixelFormatARB という関数のポインタを取得し、"PFN関数名PROC"ポインタ型 の メンバ変数へ確保しています。
#pragma once #pragma comment( lib, "opengl32.lib" ) #include <windows.h> #include "gl.h" #include "wglext.h" namespace WGLextTools { using namespace System; public ref class TWGLEXT { private: static PFNWGLCHOOSEPIXELFORMATARBPROC _wglChoosePixelFormatARB; public: static void Create(); static property IntPtr wglChoosePixelFormatARB { IntPtr get(){ return (IntPtr)_wglChoosePixelFormatARB; } } }; void TWGLEXT:: Create() { _wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress( "wglChoosePixelFormatARB" ); } }
しかしこの DLL を他のプロジェクトから利用しようとすると、関数ポインタは IntPtr型 でしか渡せないので、使うたびにいちいちキャストする必要に迫られます。
BOOL ((PFNWGLCHOOSEPIXELFORMATARBPROC)TWGLEXT::wglChoosePixelFormatARB.ToPointer())( HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats )
もっとも、関数ポインタを直接渡すというのは芸がないので、この方法だとこれが限界かと思いますが、もっと何か別の高度なテクニックを使って、美しくラップする方法があるのでしょうか?
もちろん、一つ一つメソッドでくるんでいく方法もありますが、取り込みたい関数は何百とありますし、ポインタ型の引数まで適宜 IntPtr に置換していくとなると、気が遠くなってしまいます。
static bool TWGLEXT:: wglChoosePixelFormatARB(~) { return _wglChoosePixelFormatARB(~); }
何か策がありましたら、何卒ご教示下さい。
- 編集済み luxidea 2011年9月17日 18:41
回答
-
使いたい関数を一つずつラップするのが妥当でしょう。
もしくは、ある程度固まった処理でラップするかでしょうか。
(1 関数ごとじゃなく、○○する処理というくくりで、アルゴリズムも含めるとか)結局、別のマネージ層で ToPointer() やら、キャストやら、めんどくさい処理があるわけですよね?
そうであれば、OpenGL の関数を直接使う部分は C++/CLI DLL の 1 つに絞り、そこでマネージ型の変数からネイティブ型の変数にキャストするなど、泥臭い処理をラップするまでやるのが、ラッパーとしてあるべき姿かなと思います。ところで、マネージクラス(ref class)として作らないといけない理由はあるのでしょうか?
マネージクラスは C# とか、ほかのマネージ層に見せるときに利用するぐらいにとどめて、ネイティブコードで書いた方がよい部分は、ネイティブクラスにするということでいいんですが。
質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。- 編集済み AzuleanMVP, Moderator 2011年9月17日 23:09
- 回答としてマーク luxidea 2011年9月18日 3:15
すべての返信
-
使いたい関数を一つずつラップするのが妥当でしょう。
もしくは、ある程度固まった処理でラップするかでしょうか。
(1 関数ごとじゃなく、○○する処理というくくりで、アルゴリズムも含めるとか)結局、別のマネージ層で ToPointer() やら、キャストやら、めんどくさい処理があるわけですよね?
そうであれば、OpenGL の関数を直接使う部分は C++/CLI DLL の 1 つに絞り、そこでマネージ型の変数からネイティブ型の変数にキャストするなど、泥臭い処理をラップするまでやるのが、ラッパーとしてあるべき姿かなと思います。ところで、マネージクラス(ref class)として作らないといけない理由はあるのでしょうか?
マネージクラスは C# とか、ほかのマネージ層に見せるときに利用するぐらいにとどめて、ネイティブコードで書いた方がよい部分は、ネイティブクラスにするということでいいんですが。
質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。- 編集済み AzuleanMVP, Moderator 2011年9月17日 23:09
- 回答としてマーク luxidea 2011年9月18日 3:15
-
毎度お世話になります。
使いたい関数を一つずつラップするのが妥当でしょう。
やはりそういうことですよね。了解しました。OpenGL の関数を直接使う部分は C++/CLI DLL の 1 つに絞り、そこでマネージ型の変数からネイティブ型の変数にキャストするなど、泥臭い処理をラップするまでやるのが、ラッパーとしてあるべき姿かなと思います。
はい、そういうことですよね。全てを覆い隠して、外からはなるべくシンプルに使って貰うと。 思想が分かってきました。ネイティブコードで書いた方がよい部分は、ネイティブクラスにするということでいいんですが。
将来的に OpemGL フレームワークとして C# からなどの利用も考えているので、なるべくマネージドで作ろうと挑戦しています。 近年のマネージド言語の台頭も、漠然とプログラムが簡単になるのかなと思っていましたが、色々とマネージドのカルチャーに慣れないと難しいものでね。 まだまだ切磋琢磨していきます。勉強になりました。この度もありがとうございます。