1

みなさん、こんにちは。私は Visual C++ での Win32 API プログラミングの初心者です。Microsoft Visual Studio 2008 Professional Edition を使用しています。ポインターに関して少し混乱しています。私は Windows プログラミングの初心者かもしれませんが、C や C++ の初心者ではないため、ポインターの概念をよく理解しています。問題の原因となっているポインターは、ダイアログ ボックスの日付と時刻のピッカー コントロールに関連付けられています。msdn のドキュメントによると、日付と時刻のピッカーはWM_NOTIFYメッセージを使用してアプリケーションと通信し、メッセージ内のLPARAMはNMHDR構造へのポインターになります。あれは-: '日付と時刻のピッカー (DTP) コントロールは、ユーザー入力を受け取るか、コールバック フィールドを処理して反応するときに、通知コードを送信します。コントロールの親は、これらの通知コードを WM_NOTIFY メッセージの形式で受け取ります。

これで、WM_NOTIFY メッセージを受信したときに LPARAM を NMHDR のポインターに型キャストするだけで、NMHDR 構造体にアクセスできるようになりました。それは次のとおりです-:

case WM_NOTIFY:
            if ((((NMHDR*)lparam)->idFrom == IDC_DATETIMEPICKER)&&
                ((NMHDR*)lparam)->code == DTN_DATETIMECHANGE)
            { LPNMDATETIMECHANGE lpChange=(LPNMDATETIMECHANGE)lparam;
            DisplayTime(&(lpChange->st));
                MessageBox(NULL,"wm_notify","test",MB_OK);
            }
            return TRUE;

しかし、このコード フラグメントの 4 行目を見てください。NMHDR 構造体にキャストした同じ lparam を NMDATETIMECHANGE 構造体にキャストしています。

私の質問は、これはどのように可能ですか? 1 つのパラメーターを、2 つの異なる構造を参照する 2 つの異なるポインターにキャストするにはどうすればよいですか? NMHDR 構造と LPNMDATETIMECHANGE 構造は、根本的に異なる構造です。ここで確認できます-: NMHDRおよびNMDATETIMECHANGE

これはどのように可能ですか?ポインターの値を別のデータ型を持つ他の変数にまとめて格納し、それを使用したいときに再度キャストすることが可能であることを私は知っています。しかし、単一のポインターが 2 つの異なる構造体をまとめて指すようにするにはどうすればよいでしょうか。つまり、 NMHDR構造とNMDATETIMECHANGE構造がメモリ内の同じエンティティであるとは思わないので、単一のポインターが両方を同時に参照するにはどうすればよいでしょうか? それらは完全に2つの異なるメモリアドレスを持っていると思いますか? ああ、このコードはテスト済みで、動作することに注意してください。私のソースコードは次のとおりです-:

#include <Windows.h>
#include <CommCtrl.h>
#include <cstdio>
#include "resource.h"

#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")

LRESULT CALLBACK WindowFunc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK DialogFunc(HWND, UINT, WPARAM, LPARAM);

VOID InitOptions(HWND);
VOID DisplayTime(SYSTEMTIME*);

char szWinName[]="Timer Main Window";
HWND hDlg=NULL;
HINSTANCE hInst;

int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst,
                   LPSTR lpszArgs, int nWinMode)
{
    HWND hwnd;
    MSG msg;
    WNDCLASSEX wndclass;

    wndclass.cbSize=sizeof(WNDCLASSEX);

    wndclass.hInstance=hThisInst;
    wndclass.lpszClassName=szWinName;
    wndclass.lpfnWndProc=WindowFunc;
    wndclass.style=0;

    wndclass.hIcon=LoadIcon(hThisInst,MAKEINTRESOURCE(IDI_ICON1));
    wndclass.hIconSm=LoadIcon(hThisInst,MAKEINTRESOURCE(IDI_ICON2));
    wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);

    wndclass.lpszMenuName=NULL;
    wndclass.cbClsExtra=0;
    wndclass.cbWndExtra=0;

    wndclass.hbrBackground=(HBRUSH) GetStockObject(LTGRAY_BRUSH);

    if(!RegisterClassEx(&wndclass)) return 0;

    InitCommonControls();

    hInst=hThisInst;

    hwnd=CreateWindow(
        szWinName,
        "Auto Timer (Work in progress)",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL,
        hThisInst,
        NULL
        );


    while(GetMessage(&msg, NULL, 0, 0)>0)
    { if (!hDlg||!IsDialogMessage(hDlg,&msg))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    }
    return msg.wParam;

}

LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message, WPARAM wparam, 
                            LPARAM lparam)
{ 
    switch(message){
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        case WM_CREATE:
            hDlg=CreateDialog(hInst,MAKEINTRESOURCE(IDD_FORMVIEW),
                hwnd,(DLGPROC)DialogFunc);
            break;
        default:
            return DefWindowProc(hwnd,message,wparam,lparam);
    }
    return 0;
}
BOOL CALLBACK DialogFunc(HWND hwnd, UINT message, 
                         WPARAM wparam, LPARAM lparam)
{ 
  switch(message)
    {
    case WM_INITDIALOG:
        SendMessage(hwnd,WM_SETICON, ICON_SMALL , 
            (LPARAM)LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON2)));
        return TRUE;
    case WM_CTLCOLORSTATIC:
        if (SendDlgItemMessage(hDlg,IDC_COMBO,CB_GETCOUNT,0,0)<6)
        {
            InitOptions(hDlg);
        }
        return (INT_PTR)GetStockObject(WHITE_BRUSH);
    case WM_NOTIFY:
        if ((((NMHDR*)lparam)->idFrom == IDC_DATETIMEPICKER)&&
            ((NMHDR*)lparam)->code == DTN_DATETIMECHANGE)
        { LPNMDATETIMECHANGE lpChange=(LPNMDATETIMECHANGE)lparam;
        DisplayTime(&(lpChange->st));
            MessageBox(NULL,"wm_notify","test",MB_OK);
        }
        return TRUE;
    case WM_COMMAND:
        switch LOWORD(wparam)
        { case IDC_BUTTON1:
        /*
          Button Code here.
          */
            if (SendDlgItemMessage(hDlg,IDC_RADIO5,BM_GETSTATE,0,0)==BST_CHECKED)
            { MessageBox(NULL,"radio5","test",MB_OK);
            }
            return TRUE;
        case IDC_RADIO5:
        EnableWindow(GetDlgItem(hDlg,IDC_COMBO),TRUE);
        EnableWindow(GetDlgItem(hDlg,IDC_DATETIMEPICKER),FALSE);
        EnableWindow(GetDlgItem(hDlg,IDC_DATETIMEPICKER1),FALSE);
        return TRUE;

        case IDC_RADIO6:
        EnableWindow(GetDlgItem(hDlg,IDC_COMBO),FALSE);
        EnableWindow(GetDlgItem(hDlg,IDC_DATETIMEPICKER),TRUE);
        EnableWindow(GetDlgItem(hDlg,IDC_DATETIMEPICKER1),TRUE);
        return TRUE;

        default:
            return FALSE;
    }
    case WM_CLOSE:
        DestroyWindow(hwnd);
        hDlg=NULL;
        PostQuitMessage(0);
        return TRUE;
}
    return FALSE;
}
VOID InitOptions(HWND hDlg){
    SendDlgItemMessage(hDlg,IDC_COMBO,CB_ADDSTRING,0,(LPARAM)("1 minute"));
    SendDlgItemMessage(hDlg,IDC_COMBO,CB_ADDSTRING,0,(LPARAM)("5 minutes"));
    SendDlgItemMessage(hDlg,IDC_COMBO,CB_ADDSTRING,0,(LPARAM)("10 minutes"));
    SendDlgItemMessage(hDlg,IDC_COMBO,CB_ADDSTRING,0,(LPARAM)("20 minutes"));
    SendDlgItemMessage(hDlg,IDC_COMBO,CB_ADDSTRING,0,(LPARAM)("30 minutes"));
    SendDlgItemMessage(hDlg,IDC_COMBO,CB_ADDSTRING,0,(LPARAM)("1 hour"));
    SendDlgItemMessage(hDlg,IDC_COMBO,CB_SETCURSEL,0,0);
    SendDlgItemMessage(hDlg,IDC_RADIO5,BM_SETCHECK,BST_CHECKED,0);
    SendDlgItemMessage(hDlg,IDC_RADIO1,BM_SETCHECK,BST_CHECKED,0);
    SendDlgItemMessage(hDlg,IDC_DATETIMEPICKER1,DTM_SETFORMAT,0,(LPARAM)"dd/MMM/yyyy");
    EnableWindow(GetDlgItem(hDlg,IDC_DATETIMEPICKER1),FALSE);
}

VOID DisplayTime(SYSTEMTIME *time)
{
    char t[500];

    sprintf_s(t,"Year=%d\n Month=%d\n Day=%d\n Hour=%d\n Minute=%d\n Seconds=%d\n",
        time->wYear,time->wMonth,time->wDay,
        time->wHour,time->wMinute,time->wSecond);
    MessageBox(NULL,t,"Test",MB_OK);
}

私のリソース スクリプトは次のとおりです。

// Microsoft Visual C++ generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32

#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE 
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE 
BEGIN
    "#include ""afxres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE 
BEGIN
    "\r\n"
    "\0"
END

#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_FORMVIEW DIALOGEX 0, 0, 298, 178
STYLE DS_ABSALIGN | DS_SETFONT | DS_SETFOREGROUND | DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW | WS_EX_NOACTIVATE
CAPTION "SR-Timer(Work in Progress)"
FONT 10, "Verdana", 400, 0, 0x0
BEGIN
    GROUPBOX        "Tasks",IDC_STATIC1,11,45,84,103,WS_GROUP,WS_EX_TRANSPARENT
    CONTROL         "ShutDown",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,19,63,44,10,WS_EX_TRANSPARENT
    CONTROL         "Restart",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,19,81,40,10,WS_EX_TRANSPARENT
    CONTROL         "Stand By",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,19,114,46,10,WS_EX_TRANSPARENT
    CONTROL         "Hibernate",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON,19,130,48,10,WS_EX_TRANSPARENT
    CONTROL         "Log Off",IDC_RADIO7,"Button",BS_AUTORADIOBUTTON,19,98,44,9,WS_EX_TRANSPARENT
    GROUPBOX        "Timing",IDC_STATIC2,196,44,90,107,WS_GROUP,WS_EX_TRANSPARENT
    CONTROL         "Pre-set Time",IDC_RADIO5,"Button",BS_AUTORADIOBUTTON,201,56,53,9,WS_EX_TRANSPARENT
    GROUPBOX        "Presets",IDC_STATIC3,206,65,68,30,0,WS_EX_TRANSPARENT
    CONTROL         "Specify Time",IDC_RADIO6,"Button",BS_AUTORADIOBUTTON,201,97,54,9,WS_EX_TRANSPARENT
    GROUPBOX        "Time",IDC_STATIC4,208,106,67,42,0,WS_EX_TRANSPARENT
    CONTROL         "",IDC_DATETIMEPICKER,"SysDateTimePick32",DTS_RIGHTALIGN | DTS_UPDOWN | WS_DISABLED | WS_TABSTOP | 0x8,213,133,58,11,WS_EX_TRANSPARENT
    PUSHBUTTON      "Schedule Task",IDC_BUTTON1,184,159,104,14,BS_CENTER,WS_EX_TRANSPARENT
    COMBOBOX        IDC_COMBO,213,78,57,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP,WS_EX_TRANSPARENT
    CONTROL         "",IDC_DATETIMEPICKER1,"SysDateTimePick32",DTS_RIGHTALIGN | WS_TABSTOP,213,116,58,13,WS_EX_TRANSPARENT
    CONTROL         118,IDC_STATIC,"Static",SS_BITMAP,0,0,299,178
END


/////////////////////////////////////////////////////////////////////////////
//
// Icon
//

// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1               ICON                    "Test.ico"
IDI_ICON2               ICON                    "small.ico"

/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO 
BEGIN
    IDD_FORMVIEW, DIALOG
    BEGIN
        BOTTOMMARGIN, 177
    END
END
#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// Bitmap
//

IDB_BITMAP1             BITMAP                  "time_back.bmp"
#endif    // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//


/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED

私のリソースヘッダーは次のとおりです-:

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Timer.rc
//
#define IDD_FORMVIEW                    101
#define IDI_ICON1                       109
#define IDI_ICON2                       110
#define IDB_BITMAP1                     118
#define IDC_DATETIMEPICKER              1002
#define IDC_RADIO1                      1003
#define IDC_RADIO2                      1004
#define IDC_RADIO3                      1005
#define IDC_RADIO4                      1006
#define IDC_BUTTON1                     1007
#define IDC_RADIO5                      1011
#define IDC_RADIO6                      1013
#define IDC_COMBO                       1015
#define IDC_STATIC1                     1017
#define IDC_STATIC2                     1018
#define IDC_STATIC3                     1022
#define IDC_STATIC4                     1023
#define IDC_COMBO1                      1024
#define IDC_DATETIMEPICKER1             1025
#define IDC_RADIO7                      1026

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        120
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1027
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

独自の VC++ プロジェクトを作成し、それをテストして、私が真実を語っているかどうかを確認できます。それでも納得できない場合は、メール ID を教えてください。プロジェクト全体をメールでお送りします。これは C のポインターの基本に反する問題であるため、助けが必要です。ありがとうございます。

4

2 に答える 2

5

よく見ると、 には最初のメンバーとしてNMDATETIMECHANGEa が含まれていることがわかりますNMHDR。これは実質的に派生クラスです。(C にはクラスがないため、厳密には派生クラスではありませんが、派生クラスの C エミュレーションです。)NMDATETIMECHANGEしたがって、へのキャストはダウンキャストです。

より正式には、それはCONTAINING_RECORD(NMDATETIMECHANGE, hdr, (NMHDR*)lparam)ですが、それは多くのタイピングであるため、ほとんどの人はそれを直接キャストにショートカットします.

于 2012-07-11T21:09:23.853 に答える
0
typedef struct tagNMDATETIMECHANGE {
    NMHDR nmhdr;
    DWORD dwFlags;
    SYSTEMTIME st;
} NMDATETIMECHANGE, *LPNMDATETIMECHANGE;

これが NMDATETIMECHANGE 構造体の定義です。最初のメンバーは NMHDR 型であることに注意してください。したがって、NMDATETIMECHANGE 構造体へのポインタを使用すると、実質的に NMHDR のベース アドレスを指していることになります。これが、LPARAM を NMHDR* および NMDATETIMECHANGE* に型キャストできる理由です。

于 2012-07-12T13:44:18.697 に答える