大家好, 我是Visual C ++中Win32 API编程的新手。我使用的是Microsoft Visual Studio 2008专业版。我对指针有点困惑。请注意,虽然我可能是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;
但请看这段代码片段的第四行。我正在将相同的lparam(我刚刚将其转换为NMHDR结构)转换为NMDATETIMECHANGE结构。
我的问题是这怎么可能?我如何将一个参数投射到引用两个不同结构的两个不同指针中? NMHDR和LPNMDATETIMECHANGE结构是根本不同的结构。您可以在此处查看:NMHDR和NMDATETIMECHANGE
这怎么可能?我知道可以将指针的值存储在具有不同数据类型的其他变量中,并且当我们想要使用它时再次将其转换回来。但是如何让一个指针指向两个不同的结构呢?我的意思是我不认为 NMHDR 和 NMDATETIMECHANGE 结构在内存中是同一个实体,那么单个指针如何同时引用它们呢?我希望他们有两个不同的内存地址?哦,请注意,此代码已经过测试,有效。我的源代码如下 - :
#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中的指针基础相违背的问题。谢谢。
答案 0 :(得分:5)
如果仔细观察,您会发现NMDATETIMECHANGE
包含NMHDR
作为其第一个成员,因此它实际上是派生类。 (不是严格意义上的派生类,因为C没有类,但它是派生类的C仿真。)因此,转换为NMDATETIMECHANGE
是一个向下倾斜。
更正式地说,这是一个CONTAINING_RECORD(NMDATETIMECHANGE, hdr, (NMHDR*)lparam)
,但这是很多打字,所以大多数人都将它缩写为直接演员。
答案 1 :(得分:0)
typedef struct tagNMDATETIMECHANGE {
NMHDR nmhdr;
DWORD dwFlags;
SYSTEMTIME st;
} NMDATETIMECHANGE, *LPNMDATETIMECHANGE;
这是NMDATETIMECHANGE结构的定义。请注意,第一个成员是NMHDR类型。因此,如果使用指向NMDATETIMECHANGE结构的指针,则实际上指向NMHDR的基址。这就是你可以将LPARAM强制转换为NMHDR *和NMDATETIMECHANGE *的原因。