使用SetProp和GetProp为窗口添加/获取额外的属性资源
使用SetProp可以给指定的窗口附加额外的资源,使用GetProp可以获取指定窗口的附加额外资源。
为了能够使他人更加容易理解,我想着重介绍这两个函数的参数。
例:
SetPropA(hwnd, "Data", (HANDLE)uuid.Data1);
SetProp的第一个参数指定你要发送的窗口句柄,第二个参数是对你发送的资源起一个名字,为了访问时根据这个名字访问,第三个参数是你要发送的数据
至于第一个参数你如何获取,就看你的想象力了,或者一会儿参考我给出的测试用例,这可能会让你阅读起来比较难以理解。
GetPropA(m_hWnd, "Data")
GetProp的第一个参数,是指定你要获取的窗口的句柄,第二个是资源的名字,这个名字就是SetProp设定的名字,该函数返回一个指针,请注意:如果你在SeetProp中发送的是一个数字,那么这个数字范围不能超过一个指针所能存储的大小,函数的返回值就是你发送的数据的地址。如果没有指定的资源,返回NULL。
下面是我的代码的实现,为了实现多个窗口循环发送附加资源,我创建了10个窗口,下面是第一个窗口,我创建了定时器。
void CDialog1::OnTimer(UINT_PTR nIDEvent) { // 发送数据/获取数据 UUID uuid; if (0 == nIDEvent) { CoCreateGuid(&uuid); HWND hwnd = ((CMyProjectDlg*)GetParent())->dlg2.m_hWnd; // 给Dialog2发数据 ULONG* value = (ULONG*)GetPropA(hwnd, "Data"); if (value) { RemovePropA(hwnd, "Data"); } auto s = SetPropA(hwnd, "Data", (HANDLE)uuid.Data1); CString str; str.Format(L"发送消息: 属性 Data,值 %d", uuid.Data1); m_listbox.InsertString(0, str); CString vl; vl.Format(L"Dialog%d", 1); ::SendMessage(GetParent()->m_hWnd, USERSEND, (WPARAM)vl.GetBuffer(), uuid.Data1); // 告诉主窗口,本窗口发送了什么数据 } if (1 == nIDEvent) { ULONG* value = (ULONG*)GetPropA(m_hWnd, "Data"); if (value != NULL) { CString str; str.Format(L"当前窗口的属性值:%d", (int)value); m_listbox.InsertString(0, str); ::SendMessage(GetParent()->m_hWnd, USERRECV, (WPARAM)L"Dialog1", (int)value); // 告诉主窗口,本窗口获取到什么数据 } } CDialogEx::OnTimer(nIDEvent); } void CDialog1::OnClose() { // TODO: 在此添加消息处理程序代码和/或调用默认值 KillTimer(0); KillTimer(1); RemovePropA(m_hWnd, "Data"); CDialogEx::OnClose(); }
下面是第二个窗口:
void CDialog2::OnTimer(UINT_PTR nIDEvent) { // 发送数据/获取数据 UUID uuid; if (0 == nIDEvent) { CoCreateGuid(&uuid); HWND hwnd = ((CMyProjectDlg*)GetParent())->dlg3.m_hWnd; // 给Dialog3发数据 ULONG* value = (ULONG*)GetPropA(hwnd, "Data"); if (value) { RemovePropA(hwnd, "Data"); } SetPropA(hwnd, "Data", (HANDLE)uuid.Data1); CString str; str.Format(L"发送消息: 属性 Data,值 %d", uuid.Data1); m_listbox.InsertString(0, str); CString vl; vl.Format(L"Dialog%d", 2); ::SendMessage(GetParent()->m_hWnd, USERSEND, (WPARAM)vl.GetBuffer(), uuid.Data1); // 告诉主窗口,本窗口发送了什么数据 } if (1 == nIDEvent) { ULONG* value = (ULONG*)GetPropA(m_hWnd, "Data"); if (value != NULL) { CString str; str.Format(L"当前窗口的属性值:%d", (int)value); m_listbox.InsertString(0, str); ::SendMessage(GetParent()->m_hWnd, USERRECV, (WPARAM)L"Dialog2", (int)value); // 告诉主窗口,本窗口获取到什么数据 } } CDialogEx::OnTimer(nIDEvent); } void CDialog2::OnClose() { // TODO: 在此添加消息处理程序代码和/或调用默认值 KillTimer(0); KillTimer(1); RemovePropA(m_hWnd, "Data"); CDialogEx::OnClose(); }
下面是最后一个窗口:
void CDialog10::OnTimer(UINT_PTR nIDEvent) { UUID uuid; if (0 == nIDEvent) { CoCreateGuid(&uuid); HWND hwnd = ((CMyProjectDlg*)GetParent())->dlg1.m_hWnd; // 给Dialog1发数据 ULONG* value = (ULONG*)GetPropA(hwnd, "Data"); if (value) { RemovePropA(hwnd, "Data"); } SetPropA(hwnd, "Data", (HANDLE)uuid.Data1); CString str; str.Format(L"发送消息: 属性 Data,值 %d", uuid.Data1); m_listbox.InsertString(0, str); CString vl; vl.Format(L"Dialog%d", 10); ::SendMessage(GetParent()->m_hWnd, USERSEND, (WPARAM)vl.GetBuffer(), uuid.Data1); // 告诉主窗口,本窗口发送了什么数据 } if (1 == nIDEvent) { ULONG* value = (ULONG*)GetPropA(m_hWnd, "Data"); if (value != NULL) { CString str; str.Format(L"当前窗口的属性值:%d", (int)value); m_listbox.InsertString(0, str); ::SendMessage(GetParent()->m_hWnd, USERRECV, (WPARAM)L"Dialog10", (int)value); // 告诉主窗口,本窗口获取到什么数据 } } CDialogEx::OnTimer(nIDEvent); } void CDialog10::OnClose() { // TODO: 在此添加消息处理程序代码和/或调用默认值 KillTimer(0); KillTimer(1); RemovePropA(m_hWnd, "Data"); CDialogEx::OnClose(); }
这是个窗口分别做成了一个循环发送1->2->3->...->10->1,然后自身使用GetProp来获取当前窗口的属性资源。
下面是我的主窗口的代码,这段代码与GetProp和SetProp没有关系,属于附加功能:
CMyProjectDlg::CMyProjectDlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_MYPROJECT_DIALOG, pParent) , m_size(300000) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CMyProjectDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Text(pDX, IDC_EDIT1, m_size); DDV_MinMaxInt(pDX, m_size, 1, INT_MAX); DDX_Control(pDX, IDC_LIST1, m_listbox); } BEGIN_MESSAGE_MAP(CMyProjectDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON1, &CMyProjectDlg::OnStart) ON_BN_CLICKED(IDC_BUTTON2, &CMyProjectDlg::OnStop) ON_BN_CLICKED(IDC_BUTTON3, &CMyProjectDlg::OnClear) ON_MESSAGE(USERRECV,&CMyProjectDlg::RecvMsg) ON_MESSAGE(USERSEND,&CMyProjectDlg::SendMsg) ON_WM_CLOSE() END_MESSAGE_MAP() // CMyProjectDlg 消息处理程序 BOOL CMyProjectDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != nullptr) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 dlg1.Create(IDD_DIALOG1, this); dlg2.Create(IDD_DIALOG2, this); dlg3.Create(IDD_DIALOG3, this); dlg4.Create(IDD_DIALOG4, this); dlg5.Create(IDD_DIALOG5, this); dlg6.Create(IDD_DIALOG6, this); dlg7.Create(IDD_DIALOG7, this); dlg8.Create(IDD_DIALOG8, this); dlg9.Create(IDD_DIALOG9, this); dlg10.Create(IDD_DIALOG10, this); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CMyProjectDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CMyProjectDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CMyProjectDlg::OnQueryDragIcon() { return static_cast (m_hIcon); } void CMyProjectDlg::OnStart() { start = CTime::GetTickCount(); // 显示所有的窗口 dlg1.ShowWindow(SW_SHOW); dlg2.ShowWindow(SW_SHOW); dlg3.ShowWindow(SW_SHOW); dlg4.ShowWindow(SW_SHOW); dlg5.ShowWindow(SW_SHOW); dlg6.ShowWindow(SW_SHOW); dlg7.ShowWindow(SW_SHOW); dlg8.ShowWindow(SW_SHOW); dlg9.ShowWindow(SW_SHOW); dlg10.ShowWindow(SW_SHOW); dlg1.SetTimer(0, 200, NULL); dlg1.SetTimer(1, 200, NULL); dlg2.SetTimer(0, 200, NULL); dlg2.SetTimer(1, 200, NULL); dlg3.SetTimer(0, 200, NULL); dlg3.SetTimer(1, 200, NULL); dlg4.SetTimer(0, 200, NULL); dlg4.SetTimer(1, 200, NULL); dlg5.SetTimer(0, 200, NULL); dlg5.SetTimer(1, 200, NULL); dlg6.SetTimer(0, 200, NULL); dlg6.SetTimer(1, 200, NULL); dlg7.SetTimer(0, 200, NULL); dlg7.SetTimer(1, 200, NULL); dlg8.SetTimer(0, 200, NULL); dlg8.SetTimer(1, 200, NULL); dlg9.SetTimer(0, 200, NULL); dlg9.SetTimer(1, 200, NULL); dlg10.SetTimer(0, 200, NULL); dlg10.SetTimer(1, 200, NULL); } void CMyProjectDlg::OnStop() { // TODO: 在此添加控件通知处理程序代码 if (dlg1.m_hWnd) { dlg1.KillTimer(0); dlg1.KillTimer(1); dlg2.KillTimer(0); dlg2.KillTimer(1); dlg3.KillTimer(0); dlg3.KillTimer(1); dlg4.KillTimer(0); dlg4.KillTimer(1); dlg5.KillTimer(0); dlg5.KillTimer(1); dlg6.KillTimer(0); dlg6.KillTimer(1); dlg7.KillTimer(0); dlg7.KillTimer(1); dlg8.KillTimer(0); dlg8.KillTimer(1); dlg9.KillTimer(0); dlg9.KillTimer(1); dlg10.KillTimer(0); dlg10.KillTimer(1); } } void CMyProjectDlg::OnClear() { // TODO: 在此添加控件通知处理程序代码 } // 接收子窗口发来的发送消息 LRESULT CMyProjectDlg::RecvMsg(WPARAM wparam, LPARAM lparam) { CString str; str.Format(L"%d", lparam); CString s; s = L"窗口:" + (CString)(BSTR)wparam + L"属性数据:" + str; m_listbox.InsertString(0, s); return 0; } // 接收子窗口发来的接收消息 LRESULT CMyProjectDlg::SendMsg(WPARAM wparam, LPARAM lparam) { UpdateData(); --m_size; UpdateData(FALSE); if (m_size == 0) { dlg1.KillTimer(0); dlg1.KillTimer(1); dlg2.KillTimer(0); dlg2.KillTimer(1); dlg3.KillTimer(0); dlg3.KillTimer(1); dlg4.KillTimer(0); dlg4.KillTimer(1); dlg5.KillTimer(0); dlg5.KillTimer(1); dlg6.KillTimer(0); dlg6.KillTimer(1); dlg7.KillTimer(0); dlg7.KillTimer(1); dlg8.KillTimer(0); dlg8.KillTimer(1); dlg9.KillTimer(0); dlg9.KillTimer(1); dlg10.KillTimer(0); dlg10.KillTimer(1); CTime end = CTime::GetTickCount(); CTimeSpan s = end - start; CString str = s.Format(L"总耗时:%H:%M:%S"); m_listbox.InsertString(0, str); return 1; } CString str; str.Format(L"%d", lparam); CString s; s = L"窗口:" + (CString)(BSTR)wparam + L"发送数据:" + str; m_listbox.InsertString(0, s); return 0; }
如果你在使用过程中有什么疑惑,可以通过评论来向我提问。