【问题标题】:Why doesn't FindWindowEx find IP Address window?为什么 FindWindowEx 找不到 IP 地址窗口?
【发布时间】:2019-10-13 15:43:24
【问题描述】:

如下创建了一个IP地址窗口,然后尝试使用FindWindowEx函数找到它:

    INITCOMMONCONTROLSEX icex;
    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
    icex.dwICC = ICC_INTERNET_CLASSES;
    InitCommonControlsEx(&icex);

    // hwnd is the parent of the IP address window
    HWND eIpAddress = CreateWindowW(WC_IPADDRESS,
        L"ServerIpAddress",
        WS_CHILD | WS_OVERLAPPED | WS_VISIBLE,
        MulDiv(LOWORD(units), 40, 4), 50,
        MulDiv(LOWORD(units), 70, 4),
        MulDiv(HIWORD(units), 11, 8),
        hwnd, NULL, NULL, NULL);

    // try to retrieve the control; does not work, returns null
    HWND wnd_server_ipaddress = FindWindowEx(hwnd, NULL, NULL, L"ServerIpAddress");

    DWORD err = GetLastError(); // --> returns 0

但是wnd_server_ipaddress 是 NULL。我正在对另外两个名称不同的标准编辑窗口做同样的事情,并且它正在工作。查看 Spy++ 以确保层次结构正确无误。调用后添加GetLastError(),返回0。

        // works
        HWND wnd_server_name = FindWindowEx(hwnd, NULL, NULL, L"ServerName");

        // does not work
        HWND wnd_server_ipaddress = FindWindowEx(hwnd, NULL, WC_IPADDRESS, L"ServerIpAddress");
        HWND wnd_server_ipaddress2 = FindWindow(WC_IPADDRESS, L"ServerIpAddress");

        // works
        wchar_t server_name[512] = { 0 };
        GetWindowText(wnd_server_name, server_name, 512);

        // does not work because wnd_server_ipaddress is null
        wchar_t server_ipaddress[16] = { 0 };
        DWORD dwAddr = 0x0;
        int iCount = (int)SendMessage(wnd_server_ipaddress, IPM_GETADDRESS, 0, (LPARAM)&dwAddr);
        _snwprintf_s(server_ipaddress, sizeof(server_ipaddress) / sizeof(*server_ipaddress), 16,
            L"%ld.%ld.%ld.%ld",
            (dwAddr >> 24) & 0xff,
            (dwAddr >> 16) & 0xff,
            (dwAddr >> 8)  & 0xff,
            (dwAddr)       & 0xff);

问题:是否有特定于 WC_IPADDRESS 的东西导致 FindWindowEx 找不到控件?


编辑 添加了适用于标准控件的代码。

    // creation with ServerName as lpWindowName
    HWND eName = CreateWindowW(L"Edit", L"ServerName",
        WS_CHILD | WS_VISIBLE | WS_BORDER,
        MulDiv(LOWORD(units), 40, 4), 10,
        MulDiv(LOWORD(units), 150, 4),
        MulDiv(HIWORD(units), 11, 8),
        hwnd, NULL, NULL, NULL);

    // reset text
    SetWindowText(eName, L"");

    // retrieve control - works
    HWND wnd_server_name = FindWindowEx(hwnd, NULL, NULL, L"ServerName");

    // retrieve value - works, gets whatever the text in the control is
    wchar_t server_name[512] = { 0 };
    GetWindowText(wnd_server_name, server_name, 512);

【问题讨论】:

  • 致反对者:你能解释一下这个问题到底有什么问题吗?
  • 一旦用户更改编辑字段的内容,您在标准编辑控件上使用FindWindowEx() 就会失败。
  • @RemyLebeau 我为标准编辑控件添加了整个代码。不确定我们是否在谈论同一件事,但它并没有失败。它适用于更改字段的内容,我检索用户在其中键入的内容。
  • 代码可以工作的唯一方法是如果有另一个编辑控件以ServerName 作为其文本内容。仔细检查CreateWindow()FindWindowEx() 是否返回相同的HWND。就像我在另一条评论中所说的那样,Win32 API 中没有窗口名称。窗口由其HWND 或父/子 ID 标识,而不是由名称字符串标识。

标签: c windows winapi


【解决方案1】:

IP Address controlnot a standard edit control。将"ServerIpAddress" 之类的窗口文本分配给 IP 地址控件是没有意义的,并且很可能在窗口创建过程中被丢弃。要将 IP 地址分配给 IP 地址控件,您必须使用 IPM_SETADDRESS 窗口消息。

另外,根据FindWindowEx() 文档:

如果lpszWindow参数不为NULL,FindWindowEx调用GetWindowText函数来检索窗口名称进行比较。

GetWindowText() 不适用于 IP 地址控件,就像它用于标准编辑控件一样。要从 IP 地址控件检索 IP 地址,您必须使用 IPM_GETADDRESS 窗口消息。

因此,当使用FindWindow/Ex() 时,无法通过其文本内容找到 IP 地址控件,就像标准编辑控件一样。它只能通过其WC_IPADDRESS 类名找到。

要执行您正在尝试的操作,您需要:

  1. 保存CreateWindow()返回的IP地址控件的HWND(这是首选方案):

    HWND gIpAddress; // stored somewhere that you can reach it
    
    ...
    
    // hwnd is the parent of the IP address window
    gIpAddress = CreateWindowW(WC_IPADDRESS,
        L"",
        WS_CHILD | WS_OVERLAPPED | WS_VISIBLE,
        MulDiv(LOWORD(units), 40, 4), 50,
        MulDiv(LOWORD(units), 70, 4),
        MulDiv(HIWORD(units), 11, 8),
        hwnd, NULL, NULL, NULL);
    
    ...
    
    DWORD dwAddr = 0x0;
    SendMessage(gIpAddress, IPM_GETADDRESS, 0, (LPARAM)&dwAddr);
    ...
    
  2. 为IP地址控件指定一个控件ID(在CreateWindow()hMenu参数中),然后使用GetDlgItem()获取IP地址控件的HWND时需要:

    // hwnd is the parent of the IP address window
    HWND eIPAddress = CreateWindowW(WC_IPADDRESS,
        L"",
        WS_CHILD | WS_OVERLAPPED | WS_VISIBLE,
        MulDiv(LOWORD(units), 40, 4), 50,
        MulDiv(LOWORD(units), 70, 4),
        MulDiv(HIWORD(units), 11, 8),
        hwnd, (HMENU)12345, NULL, NULL);
    
    ...
    
    // hwnd is the parent of the IP address window
    HWND wnd_server_ipaddress = GetDlgItem(hwnd, 12345);
    DWORD dwAddr = 0x0;
    SendMessage(wnd_server_ipaddress, IPM_GETADDRESS, 0, (LPARAM)&dwAddr);
    ...
    

【讨论】:

  • 我不是在尝试设置文本,而是在尝试设置窗口名称,以便以后能够找到它。我更新了问题:我正在使用IPM_GETADDRESS,但它不起作用,因为我需要发送窗口句柄。所以问题是我怎样才能找到那个窗口句柄(稍后,在点击按钮处理程序中)?我应该在父窗口打开时在全局级别保留对它的引用吗?
  • 使用g_wndipaddressat main.c 文件级别并在窗口打开时将控件的引用存储在其中。但仍然想知道是否有一种方法可以在不使用全局变量的情况下检索 IP 地址。另外我不明白你所说的文本内容是什么意思,虽然参数只是“类名”和“窗口标题”。
  • @supafly "我没有尝试设置文本,我试图设置窗口名称" - 您不能为窗口指定名称,即不是 lpWindowName 参数的实际用途,尽管它的名称。阅读documentation:“如果窗口样式指定了标题栏,则在标题栏中显示lpWindowName所指向的窗口标题。使用CreateWindow创建控件时,例如按钮、复选框和静态控件,使用lpWindowName 指定**控件的文本"
  • @supafly "我怎样才能找到那个窗口句柄(稍后,在点击按钮处理程序中)?" - 如果你不保存你创建的 HWND,那么您将不得不枚举父控件,查看它们的类名,直到找到 IP 地址控件。您可以为此使用FindWindowEx(),或者在其回调中使用EnumChildWindows() 调用GetClassName()。 “我应该在父窗口打开时在全局级别保留对它的引用吗?” - 是的,当然,如果您打算与之交互,您应该保留对您创建的 HWND 的引用它根本没有。不要在不需要的时候寻找它。
  • @supafly 或者,如果您不想保存 IP 地址控件的 HWND,则可以改为分配 子控件 ID(通过 @ 987654359@ 参数CreateWindow() 时使用WS_CHILD 样式)到IP 地址控件,然后在需要时使用GetDlgItem() 从它的ID 中获取控件的HWND,如果您可以访问父级的HWND .我更新了我的答案以表明这一点。
猜你喜欢
  • 2012-05-13
  • 1970-01-01
  • 1970-01-01
  • 2013-01-29
  • 2011-07-08
  • 2011-11-28
  • 2020-05-22
  • 2022-01-02
相关资源
最近更新 更多