DialogBoxParamによるグローバル変数の節約方法について


MK  2013-05-02 20:53:00  No: 73682  IP: 192.*.*.*

#include <windows.h>

#include "resource.h"
//#include <tchar.h>

char szClassName[] ="dialog02";  //ウィンドウクラス

//POINTS start,end,old_end;
HINSTANCE hInst;  //インスタンスハンドル
HWND hDlg;        //モードレスダイアログボックスのハンドル
char szName[32];   //ダイアログボックスから入力された文字列
HWND hMain;



//ダイアログプロシージャ
BOOL CALLBACK MyDlgProc(HWND hDlg,UINT msg, WPARAM wp, LPARAM lp)
{
  static HWND hParent;
    
//  static char szName[32];   //ダイアログボックスから入力された文字列


  switch(msg){
    case WM_INITDIALOG:
      hParent = GetParent(hDlg);
      return TRUE;
    
    case WM_COMMAND:
      switch(LOWORD(wp)){
      
        case IDOK:
          GetDlgItemText(hDlg,IDC_EDIT1,szName,
                           (int)sizeof(szName) - 1);
          
          InvalidateRect(hParent,NULL,TRUE);
          return TRUE;
        case IDC_CLEAR:

          SetDlgItemText(hDlg,IDC_EDIT1,"");
          return TRUE;

        case IDC_CLOSE:
          DestroyWindow(hDlg);
          return TRUE;
      }
      return FALSE;

    case WM_CLOSE:
            DestroyWindow(hDlg);
      return TRUE;

  }
      return FALSE;
}


  
  
  

void DrawRect(HWND hWnd,POINTS beg,POINTS end)
{
  HDC hdc;
  hdc = GetDC(hWnd);
  SetROP2(hdc,R2_NOT);
  MoveToEx(hdc,beg.x,beg.y,NULL);
  LineTo(hdc,end.x,beg.y);
    LineTo(hdc,end.x,beg.y);
    LineTo(hdc,end.x,end.y);

  LineTo(hdc,beg.x,end.y);
    LineTo(hdc,beg.x,beg.y);
    LineTo(hdc,end.x,end.y);

  
  return;

}
//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wp,LPARAM lp)
{

  char szBuf[64];
  HDC hdc;
  
//  static BOOL bDraw;
  int kakunin;
    static HMENU hMenu;
   
  PAINTSTRUCT ps;

  
//  static char szName[32];   //ダイアログボックスから入力された文字列
  

  switch(msg){
         case WM_CREATE:         // ウィンドウが作られたとき
      hMenu = GetMenu(hWnd);
      break;

    case WM_INITMENU:
      
      if(IsWindow(hDlg)){
        EnableMenuItem(hMenu,IDM_DLG,
                     MF_BYCOMMAND|MF_GRAYED);

        EnableMenuItem(hMenu,IDM_CLOSEDLG,
                     MF_BYCOMMAND|MF_ENABLED);
      }else{
          EnableMenuItem(hMenu,IDM_DLG,
                     MF_BYCOMMAND|MF_ENABLED);

        EnableMenuItem(hMenu,IDM_CLOSEDLG,
                     MF_BYCOMMAND|MF_GRAYED);

      }

      DrawMenuBar( hWnd );  // メニューバーを再描画する
      break;
    case WM_COMMAND:
      switch(LOWORD(wp)){
        case IDM_END:
          SendMessage(hWnd,WM_CLOSE,0,0);
          break;
        case IDM_HELP:
          MessageBox(hWnd,
            "Copyright(C)2004 Y.Kumei\nメニュー",
            "about",MB_OK);
          break;

        case IDM_DLG:
          hDlg = CreateDialog(hInst,"MYDLG",hWnd,(DLGPROC)MyDlgProc);
          ShowWindow(hDlg,SW_NORMAL);
        
                  //DialogBoxParam(hInst,"MYDLG",hWnd,(DLGPROC)MyDlgProc,(LPARAM)IDC_EDIT1);
          


          break;
        case IDM_CLOSEDLG:
          DestroyWindow(hDlg);

              break;
      
      }
    
    case WM_PAINT:
       
      if(strcmp(szName,"")==0)
        //strcpy(szBuf,"まだ名前の入力はありません");  //警告表示が出るから
        strcpy_s(szBuf,"まだ名前の入力はありません");
      else
        wsprintf(szBuf,"入力された氏名は%sさんです",
                       szName);
      hdc=BeginPaint(hWnd,&ps);
      TextOut(hdc, 10, 10, szBuf,(int)strlen(szBuf));
      EndPaint(hWnd,&ps);
      

            break;

     
    
    case WM_RBUTTONDOWN:
    
            kakunin = MessageBox(hWnd,"終了しますか?","終了確認",MB_YESNO);
      
      if(kakunin == IDYES){
         DestroyWindow(hWnd);
      }
      
      
      break;
    case WM_CLOSE:
      if(IsWindow(hDlg)){
        MessageBox(hWnd,"ダイアログを破棄します","破棄",MB_OK);
        DestroyWindow(hDlg);
      }
      DestroyWindow(hWnd);
      break;

      case WM_DESTROY:
       PostQuitMessage(0);
       break;
    default:
      return (DefWindowProc(hWnd,msg,wp,lp));
  }
  return 0;
}

//ウィンドウクラスの登録
ATOM InitApp(HINSTANCE hInst)
{
  WNDCLASSEX wc;
  wc.cbSize = sizeof(WNDCLASSEX);
  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc = WndProc;   //プロジャー
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hInstance = hInst;       //インスタンス
  wc.hIcon = NULL;
  wc.hCursor =(HCURSOR)LoadImage(NULL,
    MAKEINTRESOURCE(IDC_ARROW),
    IMAGE_CURSOR,
    0,
    0,
    LR_DEFAULTSIZE | LR_SHARED);
  wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  wc.lpszMenuName = "MYMENU";   //メニュー名
  wc.lpszClassName = (LPCSTR)szClassName;
  wc.hIconSm = NULL;

  return (RegisterClassEx(&wc));
}
//ウィンドウの作成
BOOL InitInstance(HINSTANCE hInst,int nCmdShow)
{
  HWND hWnd;

  hWnd = CreateWindow(szClassName,
       //タイトルバーにこの名前が表示されます
       "猫でもわかるダイアログボックス",
       WS_OVERLAPPEDWINDOW,    //ウィンドウの種類
       CW_USEDEFAULT,          //X座標
       CW_USEDEFAULT,          //Y座標
       CW_USEDEFAULT,//CW_USEDEFAULT,          //幅
       CW_USEDEFAULT,//CW_USEDEFAULT,         //高さ
       NULL,                  //親ウィンドウのハンドル、親を作る時は、NULL
       NULL,                  //メニューハンドル、クラスメニュー
                              //使う時は、NULL
       hInst,                //インスタンスハンドル
       NULL);
  if(!hWnd)
    return FALSE;
    ShowWindow(hWnd,nCmdShow);
  UpdateWindow(hWnd);
  hMain = hWnd;
  return TRUE;
}


int WINAPI WinMain(HINSTANCE hCurInst,HINSTANCE hPrevInst,
           LPSTR     lpsCmdLine,int  nCmdShow)
{
    MSG msg;
  BOOL bRet;
    HACCEL hAccel;

  hInst = hCurInst;    //グローバル変数に
                         //インスタンスハンドルをコピー


    if(!InitApp(hCurInst))
    return FALSE;
  if(!InitInstance(hCurInst,nCmdShow))
    return FALSE;

   hAccel = LoadAccelerators(hCurInst,"MYACCEL");

  while((bRet = GetMessage(&msg,NULL,0,0)) != 0){
    if(bRet == -1){
    //  MessageBox(NULL,"GetMessageエラー","Error",MB_OK);
      break;
    }else{
      if(!hDlg || !IsDialogMessage(hDlg,&msg)){
        if(!TranslateAccelerator(hMain,hAccel,&msg)){
          TranslateMessage(&msg);
          DispatchMessage(&msg);
        }
      }

    }
  }

    return (int)msg.wParam;
}

編集 削除
MK  2013-05-02 20:56:37  No: 73683  IP: 192.*.*.*

ダイアログボックス上のエディットコントロールなどに入力れたデータをメインウィンドウで利用したい場合、グローバル変数を利用しなくてはなりません。これでは、グローバル変数うがどんどん増えてしまいます。これを解決する方法としてDialogBoxParamを使用しますと記載しています。
ネットでいろいろ見えていますがコーディング方法がわからないのでご教授頂ければ幸いです。

編集 削除
仲澤@失業者  2013-05-03 10:00:35  No: 73684  IP: 192.*.*.*

C言語ですか(質問)。C++を使うとDLGとそれが扱うデータをひとくくりにして
寿命をコントロールしやすいのでDialogBoxParam()を使う場面はだいぶ減ります。

詳しくは解説しませんが、

1.DialogBoxParam()の、第5引数に任意の32bit値を渡す。
2.受け取り側の当該DLGのコールバックは、
  WM_INITDIALOGの時のLPARAMに、先の32bit値を受け取ることができる。
3.当たり前だが、この32bit値はある構造を持つデータのポインタでもOK。

という仕組みです。以上の事から、以下の制限があります。

4.受け渡すデータ(構造体のポインタなど)の寿命は、
  受け取り側のDLGの寿命より長くなくてはならない。

つまり、ローカルな変数など、スコープを抜けると
なくなっちゃうような物を渡してはだめなわけですね。
以上の仕組みを疑似的コードにすると

// 主データ構造
typedef struct DATA_MAIN{
   int     data1;
   int     data2;
}DATA_MAIN;

DATA_MAIN DataMain;// 主データのインスタンス

// 主ウインドウコールバック
WndProc(...){
  :
  DialogBoxParam( hInst,"MYDLG",hWnd,
      (DLGPROC)MyDlgProc, (LPARAM)&DataMain);
  :
}

// DLG のコールバック
MyDlgProc(HWND hDlg,UINT msg, WPARAM wp, LPARAM lp){
    static DATA_MAIN *  pDatatMain_for_DLG;
    switch( msg){
    case WM_INITDIALOG:
        // 主データのポインタを取得
        pDatatMain_for_DLG = ( DATA_MAIN *)lp;
        // Editにデータを設定
        SetDlgItemInt(hDlg,ID_EDIT1,pDatatMain_for_DLG->data1, TRUE);
        break;
    case IDOK:
         // Editの設定値を取得し、主データに戻す
        pDatatMain_for_DLG->data1
            = GetDlgItemInt(hDlg,ID_EDIT1,NULL,TRUE);
        EndDialog(...);
        break;
    }
}

編集 削除