2014-01-24 64 views
1

我用下面的代码获取HWND->i但是当我开始它对话框终止程序“的Program.exe遇到了问题,需要关闭”:是否可以在MessageBox()中显示HWND-> i?

#include <windows.h> 
#include <sstream> 

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; 

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 
        PSTR szCmdLine, int iCmdShow) 
{ 
    static TCHAR szAppName[] = TEXT ("Program") ; 
    HWND   hwnd ; 
    MSG   msg ; 
    WNDCLASS  wndclass ; 

    wndclass.style   = CS_HREDRAW | CS_VREDRAW ; 
    wndclass.lpfnWndProc = WndProc ; 
    wndclass.cbClsExtra = 0 ; 
    wndclass.cbWndExtra = 0 ; 
    wndclass.hInstance  = hInstance ; 
    wndclass.hIcon   = LoadIcon (NULL, IDI_APPLICATION) ; 
    wndclass.hCursor  = LoadCursor (NULL, IDC_ARROW) ; 
    wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; 
    wndclass.lpszMenuName = NULL ; 
    wndclass.lpszClassName = szAppName ; 

    if (!RegisterClass (&wndclass)) 
    { 
      MessageBox (NULL, TEXT ("Error"), szAppName, MB_ICONERROR) ; 
      return 0 ; 
    } 
    hwnd = CreateWindow (szAppName, 
          TEXT ("Program"), 
          WS_OVERLAPPEDWINDOW, 
          CW_USEDEFAULT, 
          CW_USEDEFAULT, 
          CW_USEDEFAULT, 
          CW_USEDEFAULT, 
          NULL, 
          NULL, 
          hInstance, 
          NULL) ; 

    ShowWindow (hwnd, iCmdShow) ; 

    std::ostringstream oss; 
    oss << hwnd->i; 
    //MessageBox(NULL, oss.str().c_str(), TEXT("message"), MB_OK); 

    while (GetMessage (&msg, NULL, 0, 0)) 
    { 
      TranslateMessage (&msg) ; 
      DispatchMessage (&msg) ; 
    } 
    return msg.wParam ; 
} 

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    switch (message) 
    { 
    case WM_DESTROY: 
      PostQuitMessage (0) ; 
      return 0 ; 
    } 
    return DefWindowProc (hwnd, message, wParam, lParam) ; 
} 

当我注释掉

oss << hwnd->i; 

程序正常运行。

那么,有没有办法在MessageBox()中显示hwnd->i

+1

'HWND'是一个不透明的指针给你,我通常不会被用户解除引用。 – legends2k

+0

你能解释一下你在哪里得到'HWND'指向一个拥有'i'成员的结构的想法吗? – Kaz

+0

@Kaz它在MinGW安装文件夹的include \ windef.h中。有一个宏'DECLARE_HANDLE(HWND);'扩展为'typedef struct HWND __ {int i;} * HWND'。 'DECLARE_HANDLE()'宏在include \ winnt.h中。 – user1257

回答

1

因为它说,在MSDN here

Windows是对象 - 他们有代码和数据 - 但他们不是 C++类。相反,程序通过使用称为句柄的值 来引用窗口。手柄是不透明的类型。本质上,它只是操作系统用来识别对象的一个​​ 数字。您可以将 图片视为具有已创建 的所有窗口的大表。它使用这个表格通过他们的手柄来查找窗口。 (这是否正是它的内部工作原理并不重要。)窗口句柄的数据类型为HWND,通常发音为 “aitch-wind”。窗口句柄由创建 窗口的函数返回:CreateWindowCreateWindowEx

而且关键的是,此评论:

请记住,手柄不是指针。如果hwnd是 包含句柄的变量,则尝试通过编写 * hwnd来解除引用句柄,这是一个错误。

重要的是,HWND只是你传递给API处理窗口的API调用。它的内部实现是隐藏的,不受开发人员的关注。通过调用HWND->i,您试图将其解引用,就好像它是一个指针一样,事实并非如此。因此你会崩溃。

0

HWND本身重复一个窗口,它看起来要引用的内部结构仅作为占位符。

实际上,它是由Windows API用来映射数据的索引,这些数据留在进程外的窗口管理器中,甚至不可见。

它明显指向的地址不属于你的程序(甚至可能不是一个地址),因此访问hwnd->i是未定义的行为:如果你幸运的话程序崩溃(从而显示错误),否则它将访问随机数据。

1

其他人已经解释了为什么取消引用HWND崩溃(它并不指向应用程序拥有的内存),但没有人解释了为什么编译器会接受HWND->...语法。

它是促进STRICT type checking在编译时:

STRICT定义,数据类型定义 变化如下:

  • 具体句柄类型被定义为相互 排斥;例如,您将无法通过 和HWND,其中HDC类型参数是 必需的。如果没有STRICT,则所有句柄均定义为整数 ,所以编译器不会阻止您使用 预期的另一种类型的另一种类型的句柄。

当未定义STRICTHWND被定义为无类型指针:

typedef void *HANDLE; 
typedef HANDLE HWND; 

因此HWND->...是在编译时无效,因为void没有任何成员。然而,当被定义STRICTHWND被定义为一个指针指向一个struct代替:

struct HWND__ { int unused; }; 
typedef struct HWND__ *HWND; 

因此HWND->...在编译时间,因为HWND__有一个成员被接受,但在运行时发生故障,因为一个HWND不实际上指向有效的HWND__实例。

至于为什么->i专门编译,您的Windows SDK头部副本可能会将unused成员定义为i而不是(例如MinGW显然会这样做)。否则,你应该得到一个关于i是未知成员的编译器错误。

+0

既然*很有趣 - 非常感谢!照明+1 :-) –