ダイアログのクラス化で仮想関数を用いて派生クラスにしているんですが・・・
ダイアログを基本クラスで静的プロシージャと派生クラスでオーバーライドしてプロシージャを使いたい
のですが、どうしても自身のポインタが取得できません。
以下にソースを載せておきます。
class CBaseWnd
{
public:
// ポインタの設定
void SetPointer( HWND hWnd );
// ウィンドウプロシージャの呼び出し
static LRESULT CALLBACK CallProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );
// ウィンドウプロシージャの実装
virtual LRESULT MainProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );
};
[クラスの実装]
//===== ポインタの設定 =====//
void CBaseWnd::SetPointer( HWND hWnd )
{
SetWindowLong( hWnd, GWL_USERDATA, (LONG)this );
}
//===== ウィンドウプロシージャの呼び出し =====//
LRESULT CALLBACK CBaseWnd::CallProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
//_プロパティリストからthisポインタを取得
//ここでポインタを取得することができないでいます。値が0です。
//先にSetWindowlongをやっても値が0のままです。
CBaseWnd* thisPtr = (CBaseWnd*)GetWindowLong( hWnd, GWL_USERDATA );
//_thisポインタが取得できなかった場合...
if( ! thisPtr )
{
//_ウィンドウの作成時の場合...
//ここでアクセス違反というエラーが起きる
if( message == WM_INITDIALOG )
thisPtr = (CBaseWnd*)((LPCREATESTRUCT)lParam)->lpCreateParams;
//_thisポインタが取得できた場合...
if( thisPtr )
{
//_プロパティリストにオブジェクトハンドル(thisポインタ)を設定する
thisPtr->SetPointer( hWnd );
}
}
//_thisポインタが取得できた場合...
if( thisPtr )
{
LRESULT lResult = thisPtr->MainProc( hWnd, message, wParam, lParam );
return lResult;
}
return DefWindowProc( hWnd, message, wParam, lParam );
}
//===== ウィンドウプロシージャの実装(継承可能) =====//
// ここでの記述はデフォルトの処理
//
LRESULT CBaseWnd::MainProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch( message )
{
//_ウィンドウが破棄された場合
case WM_DESTROY:
PostQuitMessage(0);
return 0;
//_デフォルトの場合
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
}
WM_INITDIALOGでダイアログの初期化中にポインタを取得しようとしますが、アクセス違反が起こり失敗します。
どなたか分かる方がいらっしゃったらご指摘お願いします。
No.5ベストアンサー
- 回答日時:
クラス設計において、あまり静的プロシージャを使ったことが無かった為、調べるのに時間が掛かりました。
静的プロシージャ(CallProc)から静的でないプロシージャ(SetPointer)は呼び出せないのではないかと思い、VCで以下の検証プログラムを組んでみました。
しかし、VC環境で動くことを確認しました。
まず、DialogBox関数ではWM_INITDIALOG時にlParamを渡すことはできなさそうです。
試したわけではありませんが、以下のソースコードをベースにするとmain関数の中で以下のようにする必要があるのでは?
※CBaseを継承したクラスのインスタンスを生成して、そのインスタンスのアドレスを渡す。
CreateDialogParam(
hInstance,
"Template",
hWndParent,
(WNDPROC)CBase::CallProc,
&dbobj
);
しかし、まーよくこんなトリッキーなコードが思いつくものだ。。。
●検証プログラム
#include <iostream>
using namespace std;
//****************************
//
//****************************
class CBase
{
private:
public:
static void gofnc(void *obj) {
((CBase*)obj)->func();
}
virtual void func() {
}
};
//****************************
//
//****************************
class CDBox : public CBase
{
private:
public:
void func() {
cout << "message01" << "moji" << endl;
}
};
//****************************
//
//****************************
int main()
{
CDBox dbobj;
CBase::gofnc(&dbobj);
getchar();
return 0;
}
詳しく調べてくれてとても感謝しています。
静的プロシージャから動的プロシージャを呼び出すことはできているみたいです。(なぜかはまだ分からないのですが詳しく調べてみます。)
CreateDialogParamといった関数でlParamに値を渡せば可能だとわかりました。
>しかし、まーよくこんなトリッキーなコードが思いつくものだ。。。
全くです。ネットで調べて苦戦していました。
沢山のご回答を貰ったお陰でなんとかなりました。
ありがとうございます。
No.4
- 回答日時:
こんにちは。
http://msdn.microsoft.com/ja-jp/library/cc410696 …
http://msdn.microsoft.com/ja-jp/library/cc410761 …
http://msdn.microsoft.com/en-us/library/ms645428 …
WM_INITDIALOGのlParamは、CreateDialogParam()/DialogBoxParam()等のLPARAMに指定した値が、其のまま伝わって来るのですから、
if( message == WM_INITDIALOG )
thisPtr = (CBaseWnd*)lParam;
とすれば取り出せるの筈です。
この回答への補足
これで一回試したのですが、そもそもlParamの値が0なんです。
これでは何をやってもダメなのは納得したんですが、lParamの値が0の状態のようです。
DialogBox()の引数に静的プロシージャである、CallProcを指定しているのですが、これがいけないんでしょうか?
No.3
- 回答日時:
質問とは関係ないかもしれませんが・・・
ダイアログボックスのウィンドウプロシージャにするのなら、デフォルト処理ではDefWindowProcを呼び出してはならないのでは?
この回答への補足
そうですね。
ダイアログ用のプロシージャならBOOL型にすべきなのでそうします。
これはウィンドウプロシージャのクラス化(継承可能)なソースをそのまま
転載したものなんです。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) Vba LongPtrについて教えてください 2 2022/08/19 11:14
- Visual Basic(VBA) 動かなくなってしまった古いVBAを動くようにしたい 8 2022/09/20 13:57
- JavaScript jQueryでのドラッグアンドドロップについて 1 2022/07/07 21:04
- C言語・C++・C# 関数ポインタの高速化のメリット 7 2023/05/05 20:15
- PHP アップロード画像数でCSSを分けることに成功したのですが、画像の横に文字を並べることが出来ません。 3 2023/07/28 17:16
- JavaScript Javascriptが機能せず原因が分からないので教えて頂きたいです 3 2023/06/04 14:50
- Access(アクセス) Vba Userformを前面に出すについて 3 2022/04/15 12:29
- X(旧Twitter) ツイッターでの認証 1 2023/07/22 16:26
- CGI perlで書いたcgiでsqliteの使い方を教えてください 2 2023/05/08 21:29
- Java JavaのSingletonパターンのprivateの持つ意味が分かりません。 5 2022/06/12 10:38
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語のポインタに直接アドレス...
-
C言語の関数と配列に関する質問
-
fopne で失敗する原因
-
メモリのアドレスからの値の取...
-
init関数の意味
-
戻り値で構造体を返すことは可...
-
エラーの意味
-
参照型で受け取った引数をポイ...
-
【VC++2005(CLR)】マルチスレッ...
-
TCHAR文字列内の検索について
-
セグメントエラー
-
ポインタのアドレス範囲
-
【なぜポインタを使うのか】
-
C言語のプログラムをJavaに...
-
ポインタ変数の利用方法
-
コンストラクタでnewを失敗した...
-
クイックソートの比較交換回数...
-
ポインタのミスでOS壊れるの...
-
デバイスハンドルとは?
-
#define NULL ((void *)0) の弊害
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
セグメントエラー
-
C言語のポインタに直接アドレス...
-
init関数の意味
-
戻り値で構造体を返すことは可...
-
fopne で失敗する原因
-
C言語の関数と配列に関する質問
-
Run-Time Check Failure #3とい...
-
LPSTR型の初期化について
-
ExcelVBAでのkernel32(64bit)
-
main(int argc,char **argv[])...
-
アプリを32bitから64bit移行
-
ハンドルはポインタか
-
連結リスト 要素の入れ替え
-
C言語でのconstを返す関数
-
Cで作成したDLL関数をVBから呼...
-
NULLとブランクの違い
-
エラーの意味
-
ハンドル、アドレス、ポインタ...
-
DLL<->VB間での受け渡し(文字...
-
【C言語】戻り値が構造体の関数
おすすめ情報