使用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;
}

如果你在使用过程中有什么疑惑,可以通过评论来向我提问。

相关