【问题标题】:C++ Win32 Error [closed]C++ Win32错误[关闭]
【发布时间】:2012-08-30 09:43:40
【问题描述】:

我为 Win32 做了一个类,但我不知道为什么会发生这个错误。

这是代码:

main.cpp

using namespace std;
#include "WindowManager.h"

#define   WIDTH     700
#define   HEIGHT    500
#define   VERSION   0.1

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPreviousInstance,LPSTR lpcmdline,int nCmdShow)
{
    WindowManager window("TalkToMe", 100, 100, WIDTH, HEIGHT);

    while(window.isWindowOpen())
    {
        window.PekMessage();
    }

    return 0;
}

WindowManager.h

#pragma once

#include <Windows.h>

class WindowManager
{
private:
    MSG msg;
    HWND window;

    int stat;
public:
    WindowManager(LPCTSTR title,int x, int y, int width, int height);
    ~WindowManager();
    LRESULT CALLBACK WindowProcedure(HWND winhan,UINT uint_Message,WPARAM parameter1,LPARAM parameter2);

    inline bool isWindowOpen()   { return stat != -1; }
    int  getStat()               { return stat; }
    void PekMessage();
};

WindowManager.cpp

#include "WindowManager.h"

void WindowManager::PekMessage()
{
    if(PeekMessage(&msg, window, 0, 0, PM_REMOVE))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

LRESULT CALLBACK WindowManager::WindowProcedure(HWND winhan,UINT uint_Message,WPARAM parameter1,LPARAM parameter2)
{
    switch(uint_Message)
    {
        case 16: // exit button
            stat = -1;
        break;
    }

    return DefWindowProc(winhan,uint_Message,parameter1,parameter2);
}

WindowManager::WindowManager(LPCTSTR title,int x, int y, int width, int height)
{
    stat = 0;

    WNDCLASSEX wnd;
    wnd.cbSize = sizeof(wnd);
    wnd.style  = CS_HREDRAW | CS_VREDRAW;
    wnd.lpfnWndProc = WindowProcedure;
    wnd.cbClsExtra  = 0;
    wnd.cbWndExtra  = 0;
    wnd.hInstance   = GetModuleHandle(NULL);
    wnd.hIcon       = NULL;
    wnd.hCursor     = LoadCursor(NULL,IDC_ARROW);
    wnd.hbrBackground = GetSysColorBrush(NULL);
    wnd.lpszClassName = "TalkToMe";
    wnd.lpszMenuName  = NULL;
    wnd.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

    RegisterClassEx(&wnd);

    window = CreateWindowEx(WS_EX_CONTROLPARENT, wnd.lpszClassName, title, 
        WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, x, y, width, height,NULL, NULL, 
        GetModuleHandle(NULL), NULL);
}

WindowManager::~WindowManager()
{
    DestroyWindow(window);
}

这是奇怪的构建失败:

1>------ Build started: Project: Client, Configuration: Debug Win32 ------
1>  WindowManager.cpp
1>c:\users\user\documents\visual studio 2012\projects\talktome\talktome\windowmanager.cpp(31): error C3867: 'WindowManager::WindowProcedure': function call missing argument list; use '&WindowManager::WindowProcedure' to create a pointer to member
1>c:\users\user\documents\visual studio 2012\projects\talktome\talktome\windowmanager.cpp(31): error C2440: '=' : cannot convert from 'LRESULT (__stdcall WindowManager::* )(HWND,UINT,WPARAM,LPARAM)' to 'WNDPROC'
1>          There is no context in which this conversion is possible
1>  Generating Code...
1> Compiling...
1>  Main.cpp
1>  Generating Code...
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

【问题讨论】:

  • 即使您的程序运行正常,PeekMessage 也不会阻止调用者。这意味着您的程序即使在空闲时也会消耗 CPU。你应该使用GetMessage
  • 看起来答案在错误消息中:&WindowManager::WindowProcedure。见crawfordology.net/tips/code/c++/member-pointers.html

标签: c++ winapi


【解决方案1】:

这是意料之中的。 WindowManager::WindowManager 有一个隐藏的 this 参数,因此它不遵守 wnd.lpfnWndProc 所需的定义。

要解决此问题,您需要定义一个辅助函数,如下所示:

LRESULT CALLBACK HelperWindowProcedure(HWND winhan,UINT uint_Message,WPARAM parameter1,LPARAM parameter2)
{
    if (uint_Message == WM_CREATE)
    {
       /* Retrieve "this" sent through CreateWindowEx */
       WindowManager *wm = (WindowManager *)(((LPCREATESTRUCT) lParam)->lpCreateParams);
       /* And store it as window-private date */
       SetWindowLongPtr(winhan, GWLP_USERDATA, wm);
    }

    /* Retrieve WindowManager from window-private data */
    WindowManager *wm = (WindowManager *)GetWindowLongPtr(winhan, GWLP_USERDATA);
    /* Forward window message to WindowManager */
    wm->WindowProcedure(winhan, uint_Message, parameter1, parameter2);
}

WindowManager::WindowManager()
{
    ...
    /* use helper window procedure */
    wnd.lpfnWndProc = HelperWindowProcedure;
    ...
    /* send "this" through WM_CREATE */
    window = CreateWindowEx(WS_EX_CONTROLPARENT, wnd.lpszClassName, title, 
       WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, x, y, width, height,NULL, NULL, 
       GetModuleHandle(NULL), this);

}

【讨论】:

  • 我会使用的术语是:WindowManager::WindowManager 当前是指向成员的指针,lpfnWndProc 是指向函数的指针。
【解决方案2】:

检查解决方案:

wnd.lpfnWndProc = (WNDPROC)WindowProcedure;

LRESULT WNDPROC WindowManager::WindowProcedure(HWND winhan,UINT uint_Message,WPARAM parameter1,LPARAM parameter2)

【讨论】:

  • -1,这是一个糟糕或危险的建议。试图通过“抛弃它”来修复这样的错误只是隐藏了问题,并没有解决它。应避免对函数进行强制转换;它们通常不是不必要的,或者表明存在错误或其他问题。这里真正的问题是 WindowProcedure 是一个成员函数,但是 Win32 需要一个静态函数来用作回调;投射在这里无济于事。
  • LRESULT WNDPROC 这是标准的非危险建议,不是 LRESULT CALLBACK
  • "LRESULT WNDPROC ..." 没有意义,不会编译; WNDPROC 被定义为一个指向窗口过程的指针; CALLBACK 只是修改函数的调用约定。您可以将 CALLBACK 与返回类型结合使用,但不能使用“LRESULT WNDPROC”,因为它试图指定两种返回类型!无论如何,我的主要观点是你不应该抛弃问题。如果您一开始就正确定义了函数,则不需要强制转换。 (也许在 Win32 中强制转换函数唯一有效的地方是 GetProcAddress。)
【解决方案3】:

正如 user1202136 所提到的,C++ 类方法具有隐式参数,无论何时调用它都会传递给函数。它保存指向类实例的指针(this 指针)并允许您访问类变量。为了解决这个问题,您可以将WindowProcedure 方法设为静态并在窗口内存中使用GWL_USERDATA 来存储您的类实例(this 指针)。查找GetWindowLongPtr 了解更多信息。创建窗口时需要通过lpParam参数传递this指针,在处理WM_CREATE消息时使用SetWindowLongPtr存储。

【讨论】:

    猜你喜欢
    • 2011-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多