2016-06-11 4 views
-1

私はWin32ダイアログボックスラッパーを開発しています。GetWindowLongPtrがガベージを返します

.hファイル

class dlg { 
    static INT_PTR CALLBACK DlgProcTmp(HWND hwnd, 
             UINT wm, WPARAM wp, LPARAM lp); 
    INT_PTR CALLBACK DlgProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp); 

    bool ismodal; 
protected: 
    HWND hwndDlg; 
    int id; 
public: 
    virtual void oncreate(const widget &w) { } 
    virtual void oncmd(const widget &w, int code, int idCntrl, HWND hwnd) { } 
    virtual void onclose(const widget &w) { } 
    dlg() { } 
    dlg(int id); 
    INT_PTR domodal(HWND hwndOwner = nullptr); 
    widget domodeless(HWND hwndOwner = nullptr, int cmdshow = SW_SHOW); 
}; 

.cppファイル

INT_PTR dlg::DlgProcTmp(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp) 
{ 
    dlg *This; 

    if (wm == WM_INITDIALOG) { 
     This = (dlg *) lp; 
     setwinlong(hwnd, DWLP_USER, This); 
     This->oncreate(widget(hwnd)); 

     return TRUE; 
    } 
    if ((This = getwinlong<dlg *>(hwnd, DWLP_USER)) != nullptr) 
     return This->DlgProc(hwnd, wm, wp, lp); 
    return FALSE; 
} 
INT_PTR dlg::DlgProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp) 
{ 
    this->hwndDlg = hwnd; 
    switch (wm) { 
     case WM_COMMAND: 
      this->oncmd(widget(hwnd), HIWORD(wp), LOWORD(wp), (HWND) lp); 
      if (this->ismodal) 
       EndDialog(hwnd, LOWORD(wp)); 
      else 
       DestroyWindow(hwnd); 
      return TRUE; 
     case WM_DESTROY: 
      this->onclose(widget(hwnd)); 
      return TRUE; 
    } 
    return FALSE; 
} 

ダイアログがDialogBoxParam呼び出しでdomodalに作成されます。最後の引数はthisポインタで、WM_INITDIALOGメッセージのlparamから取得します。異なるメッセージ間でthisを使用するには、thisをWM_INITDIALOGにHWNDで保存します。しかし、WM_INITDIALOGではないメッセージが到着し、GetWindowLongPtrthisポインタを取得すると、vtableが破損しているゴミのdlgクラスが返されます。私は正しいハンドラ関数を呼び出すためにvtableを使用します。その結果、私のコードは、WM_COMMANDハンドラの最初の行でクラッシュします。ここでは、デバッガがthisの値として示したものです:

enter image description here

GetWindowLongPtrがゴミを返しているのはなぜ?

BTW、getwinlongGetWindowLongPtrのラッパーであり、setwinlongSetWindowLongPtrのラッパーです。ここでは、実装されている:

template <class TYPE> static TYPE getwinlong(HWND hwnd, int idx) 
{ 
    return (TYPE) GetWindowLongPtr(hwnd, idx); 
} 
template <class TYPE> static void setwinlong(HWND hwnd, int idx, TYPE val) 
{ 
    SetWindowLongPtr(hwnd, idx, (LONG_PTR) val); 
} 

私はあなたがLONGの代わりLONG_PTRにキャスト場合GetWindowLongPtrはhttps://blogs.msdn.microsoft.com/oldnewthing/20131226-00/?p=2263のように、Win64のに失敗する方法については、多くの記事を見てきました。私は自分の問題が異なっていると信じています。

編集:私はあなたが私たちを示したコードをつなぎ合わせて、作業のサンプルを作成することができました

INT_PTR dlg::domodal(HWND hwndOwner) 
{ 
    this->ismodal = true; 
    return DialogBoxParam(gethinst(hwndOwner), 
     MAKEINTRESOURCE(id), hwndOwner, dlg::DlgProcTmp, 
     (LPARAM) this); 
} 
+1

ダイアログテンプレートで実際にユーザーデータ用に余分なスペースが指定されていますか?ダイアログ自体がそのデータを独自の目的で使用していますか?常にあります:['SetProp'](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633568%28v=vs.85%29.aspx) – theB

+0

@theBこれはどういう意味ですか? https://msdn.microsoft.com/en-us/library/windows/desktop/ms645398(v=vs.85).aspx – user3144238

+1

このダイアログのインスタンスを作成するコードを投稿できますか? – andlabs

答えて

2

@andlabsがダイアログを作成するコードを望んでいました

#pragma once 
#include <Windows.h> 

class dlg { 
    static INT_PTR CALLBACK DlgProcTmp(HWND hwnd, 
             UINT wm, WPARAM wp, LPARAM lp); 
    INT_PTR CALLBACK DlgProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp); 

    bool ismodal; 
protected: 
    HWND hwndDlg; 
    int id; 
public: 
    //virtual void oncreate(const widget &w) { } 
    //virtual void oncmd(const widget &w, int code, int idCntrl, HWND hwnd) { } 
    //virtual void onclose(const widget &w) { } 
    dlg() { } 
    dlg(int id) : id(id) { } 
    INT_PTR domodal(HWND hwndOwner = nullptr); 
    //widget domodeless(HWND hwndOwner = nullptr, int cmdshow = SW_SHOW); 
}; 

dlg.cpp

dlg.h
#include "dlg.h" 


template <class TYPE> static TYPE getwinlong(HWND hwnd, int idx) 
{ 
    return (TYPE) GetWindowLongPtr(hwnd, idx); 
} 
template <class TYPE> static void setwinlong(HWND hwnd, int idx, TYPE val) 
{ 
    SetWindowLongPtr(hwnd, idx, (LONG_PTR) val); 
} 


INT_PTR dlg::DlgProcTmp(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp) 
{ 
    dlg *This; 

    if (wm == WM_INITDIALOG) { 
     This = (dlg *) lp; 
     setwinlong(hwnd, DWLP_USER, This); 
     //This->oncreate(widget(hwnd)); 

     return TRUE; 
    } 
    if ((This = getwinlong<dlg *>(hwnd, DWLP_USER)) != nullptr) 
     return This->DlgProc(hwnd, wm, wp, lp); 
    return FALSE; 
} 
INT_PTR dlg::DlgProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp) 
{ 
    this->hwndDlg = hwnd; 
    switch (wm) { 
     case WM_COMMAND: 
      //this->oncmd(widget(hwnd), HIWORD(wp), LOWORD(wp), (HWND) lp); 
      if (this->ismodal) 
       EndDialog(hwnd, LOWORD(wp)); 
      else 
       DestroyWindow(hwnd); 
      return TRUE; 
     case WM_DESTROY: 
      return TRUE; 
    } 
    return FALSE; 
} 

INT_PTR dlg::domodal(HWND hwndOwner) 
{ 
    this->ismodal = true; 
    return DialogBoxParam(GetModuleHandle(NULL), 
     MAKEINTRESOURCE(id), hwndOwner, dlg::DlgProcTmp, 
     (LPARAM) this); 
} 

main.cppに

int APIENTRY _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int) 
{ 
    dlg myDialog(IDD_DIALOG); 
    myDialog.domodal(); 

    return 0; 
} 

あなたは外で特定のコメントされたコードの公平なビットがあることに気づく、宣言のための仮想の呼び出しますメッセージ処理関数(onXXX)は省略されています。 widgetタイプの定義がないため、私はこれを行いました。実際の問題とは密接に関連しているとは思われませんでした。

仮想メッセージ処理関数が呼び出されない限り、コードは正常に機能するので、それが必要です。

私は、次のようにwidgetのスタブクラスに追加:

class widget 
{ 
public: 
    widget(HWND hWnd) 
     : m_hWnd(hWnd) 
    { } 

    HWND m_hWnd; 
}; 

をしてoncmd機能だけでなく、WM_COMMANDハンドラで、それへの呼び出しをコメント解除。ここでも、コードは正しくコンパイルされ、正しく動作します。だからあなたは何の問題が起こっているのか分かりません。これは、widgetクラスまたはあなたが私たちに示していない他のコードにある必要があります。

コードに少なくとも1つ微調整があります。 hwndDlgメンバ変数をDlgProcTemp関数内に割り当てます。これは、DlgProc関数が実行されるまで待機するのではなく、したがって、これを実行してください:

INT_PTR dlg::DlgProcTmp(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp) 
{ 
    dlg *This; 

    if (wm == WM_INITDIALOG) { 
     This = (dlg *) lp; 
     setwinlong(hwnd, DWLP_USER, This); 
     This->hwndDlg = hwnd; 
     This->oncreate(widget(hwnd)); 

     return TRUE; 
    } 
    if ((This = getwinlong<dlg *>(hwnd, DWLP_USER)) != nullptr) 
     return This->DlgProc(hwnd, wm, wp, lp); 
    return FALSE; 
} 
INT_PTR dlg::DlgProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp) 
{ 
    switch (wm) { 
     case WM_COMMAND: 
      this->oncmd(widget(hwnd), HIWORD(wp), LOWORD(wp), (HWND) lp); 
      if (this->ismodal) 
       EndDialog(hwnd, LOWORD(wp)); 
      else 
       DestroyWindow(hwnd); 
      return TRUE; 
     case WM_DESTROY: 
      return TRUE; 
    } 
    return FALSE; 
} 

using C++-style casts in preference to C-style castsを強く考えてください。

コードを正常に動作させることができない場合は、ここで行ったようにMinimal, Complete, and Verifiable exampleという質問に編集する必要があります。

+0

ありがとう、あなたの助言に従って、私は仮想関数への各呼び出しを取り出したとき、それは働き始めた。私はなぜそれが動作するようになったのかわかりませんが、あなたの助言に従っていました。 – user3144238

関連する問題