簡體   English   中英

C ++,WIN32,WndProc導致成員函數崩潰(0x88訪問沖突)

[英]C++, WIN32, WndProc to Member Function Crash (Access violation at 0x88)

我一直在寫一個win32包裝器類,但是遇到一個問題:因為該類的每個實例都有一個窗口,所以我使用SetWindowLongPtrW()this指針封裝在用戶信息空間中,從而可以調用來自靜態WndProc函數的消息處理程序。 效果很好:我可以調用該函數。 但是,當我嘗試從消息處理程序中調用另一個成員函數時,在0x00000088處出現訪問沖突。它確實會編譯。 我發表了很多文章,因為老實說,我不太確定問題的根源...請隨意評論/批評我的代碼。 謝謝您的幫助!

這是標題:

#pragma once
#include <Windows.h>
#include "GlobalDefines.h"
#include "GraphicsWrapper.h"
#include "Keyboard.h"

namespace Startup
{

class GraphicsWrapper;

class WindowsWrapper
{
public:
    WindowsWrapper(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   INT nCmdShow);
    ~WindowsWrapper();
    void EnterMsgLoop(GraphicsWrapper* Gfx);
    static LRESULT _stdcall WindowProc(HWND hWnd,
                                       UINT message,
                                       WPARAM wParam,
                                       LPARAM lParam);
    LRESULT _stdcall MessageHandler(HWND hWnd,
                                    UINT message,
                                    WPARAM wParam,
                                    LPARAM lParam);
    WNDCLASSEX WndClass;
    MSG Message;
    RECT Desktop;
    RECT Taskbar;
    RECT WindowCoordinates;
    LPSTR CommandLineArgs;
    INT CmdShow;
    HINSTANCE TheInstance;
    HWND WindowHandle;

    void InitializeWndClassEx();
    void InitializeWindowHandleHWND();
    void ShowWindowOnScreen();
    bool GetScreenRect(RECT & Desktop);
    bool GetTaskbarRect(RECT& rectTaskbar);
    bool GetWindowCoords(RECT& WindowCoordinates);
    int GetTaskbarSide();
    enum TaskbarSides
    {
        Top,
        Right,
        Bottom,
        Left
    };
    void SetFullScreen(bool Enable);
};

static IO::Keyboard * kbd;
}

這是實施的相關部分。 我將標記崩潰發生的位置。

void Startup::WindowsWrapper::InitializeWndClassEx()
{
    WndClass.hIcon = LoadIcon(TheInstance,(MAKEINTRESOURCE(IDI_MAIN_ICON) ) );
    WndClass.hIconSm = LoadIcon(TheInstance,(MAKEINTRESOURCE(IDI_MAIN_ICON) ) );
    WndClass.cbSize = sizeof(WNDCLASSEX);
    WndClass.style = CS_HREDRAW | CS_VREDRAW;
    WndClass.lpfnWndProc = WindowProc;
    WndClass.hInstance = TheInstance;
    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClass.lpszClassName = L"WindowClassName";
    RegisterClassEx(&WndClass);
    SetWindowLongPtrW(WindowHandle, GWLP_USERDATA, (long)this);
}

void Startup::WindowsWrapper::SetFullScreen(bool Enable)
{

    long style = Enable ? WS_POPUP : WS_OVERLAPPED | WS_SYSMENU;
    static RECT windowRect = {};
    static bool needRect = true;

    if (needRect)
    {
        GetWindowRect(WindowHandle, &windowRect);
        needRect = false;
    }

    SetWindowLong(WindowHandle, GWL_STYLE, style);

    if (Enable)
    {
        SetWindowPos(WindowHandle, HWND_TOPMOST,
                     0,0,
                     GetSystemMetrics(SM_CXSCREEN),
                     GetSystemMetrics(SM_CYSCREEN),
                     SWP_SHOWWINDOW);
    }
    else
    {
        SetWindowPos(WindowHandle, 0,
                     windowRect.left,windowRect.top,
                     windowRect.right - windowRect.left,
                     windowRect.bottom - windowRect.top,
                     SWP_SHOWWINDOW);
    }
}

LRESULT CALLBACK Startup::WindowsWrapper::WindowProc
(
    HWND hWnd,
    UINT message,
    WPARAM wParam,
    LPARAM lParam
)
{
    WindowsWrapper* ourObjectPtr = NULL;
    long thisObject = GetWindowLongW(hWnd, GWLP_USERDATA);

    ourObjectPtr = (WindowsWrapper *)( (void*)thisObject);

    long Result = ourObjectPtr->MessageHandler(hWnd, message, wParam, lParam);
    RET(Result);

}

LRESULT _stdcall Startup::WindowsWrapper::MessageHandler
(
    HWND hWnd,
    UINT message,
    WPARAM wParam,
    LPARAM lParam
)
{
    switch(message)
    {
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        case WM_KEYDOWN:
            switch(wParam)
        {
            case VK_ESCAPE:
                PostQuitMessage(0); //Works fine here, but...
                break;
            case VK_SPACE:
                this->SetFullScreen(false); //Crashes here w/ access violation
                break;
            case VK_SHIFT:
                this->SetFullScreen(true); //Or here, w/ the same error.
                break;
        }           
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}

這是createWindowEx調用。 再次感謝您的幫助。

void Startup::WindowsWrapper::InitializeWindowHandleHWND()
{
WindowHandle = CreateWindowEx(NULL,
    L"WindowClassName",
            L"WindowTitle"
    WS_OVERLAPPED | WS_SYSMENU,
    WindowCoordinates.left, WindowCoordinates.top,
    WindowCoordinates.right, WindowCoordinates.bottom,
    NULL, NULL, TheInstance,
    CommandLineArgs);
}

我有一段時間以來寫的自定義對話框處理程序的一些代碼,可能對您有用。

相同的原理適用於窗口,但將WM_INITDIALOG切換為WM_CREATE ,也將DWLP_USER替換為GWLP_USERDATA 回調的格式也略有不同。 您應該可以挽救幾乎所有此功能。

LRESULT CALLBACK CDialog::DlgProc( HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
    CDialog* pWindow;

    if( msg == WM_INITDIALOG ) {
        SetWindowLongPtr( hWndDlg, DWLP_USER, (LONG_PTR)lParam );
        pWindow = reinterpret_cast<CDialog*>( lParam );
        pWindow->m_hWnd = hWndDlg;
    } else {
        pWindow = reinterpret_cast<CDialog*>( (LPARAM)GetWindowLongPtr( hWndDlg, DWLP_USER ) );
    }

    if( pWindow != NULL ) {
        LRESULT ret = pWindow->OnMessage( msg, wParam, lParam );
        if( msg == WM_NCDESTROY ) pWindow->m_hWnd = NULL;
    }

    return FALSE;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM