2012-09-05 31 views
-7

我爲Win32做了一個類,我不知道爲什麼會發生這個錯誤。C++ 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 ========== 
+0

即使你的程序工作,'PeekMessage'不會阻止調用者。這意味着你的程序即使閒置也會消耗CPU。你應該使用'GetMessage'。 – asveikau

+0

看起來像在錯誤消息中的答案:&WindowManager :: WindowProcedure。請參閱http://www.crawfordology.net/tips/code/c++/member-pointers.html –

回答

4

這是可以預料的。 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); 

} 
+2

我將使用的術語是:「WindowManager :: WindowManager」當前是指向成員的指針,「lpfnWndProc」是指針起作用。 –

-3

檢查解決方案:

wnd.lpfnWndProc = (WNDPROC)WindowProcedure; 

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

-1,這是不好或危險的建議。試圖通過「拋棄它」來修復這樣的錯誤只是隱藏了問題,但並未解決問題。應該避免在函數上投射;他們通常是不必要的,或者表明存在缺陷或其他問題。這裏真正的問題是WindowProcedure是一個成員函數,但Win32需要一個靜態函數作爲回調函數;鑄造對此無濟於事。 – BrendanMcK

+0

LRESULT WNDPROC這是標準的非危險建議,而不是LRESULT CALLBACK – theWalker

+0

「LRESULT WNDPROC ...」沒有意義,也不會編譯; WNDPROC被定義爲指向窗口過程的指針; CALLBACK只是修改一個函數的調用約定。您可以將CALLBACK與返回類型組合,但不能使用「LRESULT WNDPROC」,因爲它試圖指定兩種返回類型!無論如何,我的主要觀點是你不應該拋棄問題。如果您首先正確定義您的功能,則不需要投射。 (也許在Win32中唯一可以使用的函數是GetProcAddress。) – BrendanMcK

1

正如user1202136提到的,C++類方法具有隱式參數,每次調用時都會傳入該函數。它包含指向類實例的指針(this指針),並允許您訪問類變量。爲了解決這個問題,你可以在窗口內存中使WindowProcedure方法靜態並使用GWL_USERDATA來存儲你的類實例(this指針)。查看GetWindowLongPtr瞭解更多信息。在創建窗口時,您需要通過lpParam參數傳遞this指針,並在處理WM_CREATE消息時使用SetWindowLongPtr存儲它。