SetWindowLong(GWL_USERDATA)で起こる不具合 – プログラミング – Home

通知
すべてクリア

[解決済] SetWindowLong(GWL_USERDATA)で起こる不具合


ひな
 ひな
(@ひな)
ゲスト
結合: 23年前
投稿: 8
Topic starter  

VC++ ver7.0.9486 SDKで使っております。

IPアドレスコントロールをサブクラス化しようと、
DefControlProc = (FARPROC)GetWindowLong(HWnd, GWL_WNDPROC);
SetWindowLong(HWnd, GWL_USERDATA, (LONG)this);
SetWindowLong(HWnd, GWL_WNDPROC, (LONG)PreControlProc);
としたのですが、コントロールが上手く動作せず、
コントロールの表示もおかしくなってしまいました。

実験で、エディットコントロールでは不具合が出ませんでした。
他にSetWindowLong(GWL_USERDATA)を使わずにポインタを渡した時は不具合が出ず、
SetWindowLong(GWL_USERDATA)だけを使い、
SetWindowLong(GWL_WNDPROC)とGetWindowLong(GWL_WNDPROC)を使わなかった時には、
不具合が起こったので、SetWindowLong(GWL_USERDATA)が原因だと思うのですが、
原因がなんなのか全く思いつきません。

長いので次にソースを書きます。下に書くクラスを派生して使っています。
派生してもコントロールによる違いはSetControl(int id, CDialog *dialog)の
id(リソースのID)の違いだけです。

なにとぞご教授お願いいたします。


引用未解決
トピックタグ
ひな
 ひな
(@ひな)
ゲスト
結合: 23年前
投稿: 8
Topic starter  

このクラスを派生して使っています。
派生クラスでは値の収得、設定などしかおこなっておりません。

class CBaseControl
{
public:
CBaseControl() : ControlID(0), Dialog(NULL), HWnd(0), DefControlProc
(NULL) {}
virtual ~CBaseControl();

Bool SetControl(int id, CDialog *dialog);

protected:
virtual LRESULT ControlProc(HWND hwnd, UINT msg, WPARAM wparam,
LPARAM lparam);

int ControlID;
CDialog *Dialog; //ダイアログのハンドルを持ってるクラス
HWND HWnd;

private:
static LRESULT CALLBACK PreControlProc(HWND msg, UINT id, WPARAM
wparam, LPARAM lparam);
FARPROC DefControlProc;
};

CBaseControl::~CBaseControl()
{
if(DefControlProc)
SetWindowLong(HWnd, GWL_WNDPROC, (LONG)DefControlProc);
}

LRESULT CALLBACK CBaseControl::PreControlProc(HWND hwnd, UINT msg, WPARAM
wparam, LPARAM lparam)
{
CBaseControl *control = (CBaseControl*)GetWindowLong(hwnd,
GWL_USERDATA);
if(!control)
return 0;

return control->ControlProc(hwnd, msg, wparam, lparam);
}

LRESULT CBaseControl::ControlProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
lparam)
{
return CallWindowProc((WNDPROC)DefControlProc, hwnd, msg, wparam,
lparam);
}

Bool CBaseControl::SetControl(int id, CDialog *dialog)
{
if(!dialog) return False;
ControlID = id; Dialog = dialog;
HWnd = GetDlgItem(Dialog->GetDlgHandle(), ControlID);

DefControlProc = (FARPROC)GetWindowLong(HWnd, GWL_WNDPROC);
SetWindowLong(HWnd, GWL_USERDATA, (LONG)this);
SetWindowLong(HWnd, GWL_WNDPROC, (LONG)PreControlProc);

return True;
}

よろしくお願いいたします。


返信引用
ひな
 ひな
(@ひな)
ゲスト
結合: 23年前
投稿: 8
Topic starter  

使う時はこのようにつかっております。

CIPAddressControl : public CBaseControl として、

ダイアログボックスクラスでCIPAddressControl IPControlを定義
ダイアログのWM_INITDIALOGでIPControl.SetControl(id, this/*dialogクラス*/)
この後コントロールを操作しなくてもうまくいきません。

あと、CIPAddressControlのvirtual ControlProc()は定義せずにデフォルトを使用してま
す。うー・・・、なんか簡単なミスな気がしてきます。ミスだったらすいません。


返信引用
ku
 ku
(@ku)
ゲスト
結合: 24年前
投稿: 312
 

> 不具合が起こったので、SetWindowLong(GWL_USERDATA)が原因だと思うのですが、
> 原因がなんなのか全く思いつきません。
ためしにエディットとIPアドレスに最初からGWL_USERDATAに設定されている値を取得してみ
ました
LONG l1 = ::GetWindowLong(m_Edit.GetSafeHwnd(), GWL_USERDATA);
LONG l2 = ::GetWindowLong(m_Adr.GetSafeHwnd(), GWL_USERDATA);
エディットの方は0でしたが、IPアドレスの方は0以外でした

IPアドレスのコントロールは最初からこの領域を(何らかの理由があって)
すでに使用しているということではないでしょうか?


返信引用
ひな
 ひな
(@ひな)
ゲスト
結合: 23年前
投稿: 8
Topic starter  

kuさんお答えありがとうございます。

GWL_USERDATAの領域はこっちが自由に使える領域じゃなかったとは・・・。
前提の知識が間違ってました。すいませんでした。

これだと、ポインタは自分で管理するしかありませんね。
GWL_USERDATAの領域って使えない

お答え本当にありがとうございました。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました