简体   繁体   English

cpp WinAPI WndProc包装在类中

[英]cpp WinAPI WndProc wrapped in the class

i want to create class to instantiate windows on the fly, but since few weeks cant get it to work, and any help would be highly appreciated 我想创建可即时实例化窗口的类,但由于数周无法使其正常工作,因此我们将不胜感激任何帮助

As i was not able to retrieve correct data with GetObjectFromHandle function, i tried to use std::map to store class instances, and in constructor i can access data from the map as expected, but from message loop i can access only garbage while HWND hWnd is correct. 由于我无法使用GetObjectFromHandle函数检索正确的数据,因此我尝试使用std :: map存储类实例,并且在构造函数中我可以按预期从映射访问数据,但是从消息循环中,我只能在HWND时访问垃圾hWnd是正确的。

here is the code 这是代码

.h 。H

#ifndef BASE_WINDOW_H
#define BASE_WINDOW_H

#include "GlobalApp.h"
#include <string>
#include <map>

namespace G{
    class cWin;

    static void SetObjectToHandle( HWND hWnd, LPARAM lParam );
    static cWin *GetObjectFromHandle( HWND hWnd );

    class cWin{
        static LRESULT CALLBACK internal_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
    public:
        static std::map<HWND, cWin*> hwndMap;
        LRESULT WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
        cWin();

        int     registerCls();
        HWND    createWnd();
        HWND    hWnd;
    };
}

#endif

and .cpp 和.cpp

#include "stdafx.h"
#include "BaseWindow.h"

HWND G::cWin::createWnd(){
    HWND hWnd;
    hWnd = ::CreateWindowEx(WS_EX_WINDOWEDGE, L"div", NULL,
        WS_CHILD | WS_VISIBLE,
        50, 50, 50, 50,
        G::hWnd, NULL, G::hInst, this );

    ::UpdateWindow( hWnd );

    return hWnd;
}

int G::cWin::registerCls(){
    WNDCLASSEX wcex;

    if ( !::GetClassInfoEx(G::hInst, L"div", &wcex) ){
        wcex.cbSize = sizeof(WNDCLASSEX);

        wcex.style          = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc    = (WNDPROC)this->internal_WndProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = DLGWINDOWEXTRA;
        wcex.hInstance      = G::hInst;
        wcex.hIcon          = LoadIcon(G::hInst, MAKEINTRESOURCE(IDI_WINAPITWO));
        wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+3);
        wcex.lpszMenuName   = NULL;
        wcex.lpszClassName  = L"div";
        wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

        if ( ::RegisterClassEx(&wcex) == 0 ){
            G::Console( L"wcex_ERR" );
            return -1;
        }
    }
    return 0;
}

G::cWin::cWin(){
    this->registerCls();

    this->hWnd = this->createWnd();
    G::Console( L"wndCreated", this->hWnd );

    this->hwndMap.insert( std::pair< HWND, G::cWin*>( this->hWnd, this ) );

    G::cWin *pWnd = this->hwndMap[ this->hWnd ];
    G::Console( L"map:", pWnd->hWnd ); //point to correct data
}

LRESULT G::cWin::WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
    if ( !this->hwndMap.count( hWnd ) ){
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    G::cWin *pWnd = this->hwndMap[ hWnd ];

    switch (message){
        case WM_LBUTTONDOWN:
            G::Console( L"ButtonDown", pWnd->hWnd ); // not correct, why?
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

std::map<HWND, G::cWin*> G::cWin::hwndMap;


LRESULT CALLBACK G::cWin::internal_WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ){
    if( uMsg == WM_NCCREATE ){
        G::SetObjectToHandle( hWnd, lParam );
    }

    G::cWin *pWnd = G::GetObjectFromHandle( hWnd );

    if( pWnd ){
        return pWnd->WindowProc( hWnd, uMsg, wParam, lParam );
    } else
        return DefWindowProc( hWnd, uMsg, wParam, lParam );
}

void G::SetObjectToHandle( HWND hWnd, LPARAM lParam ){
    LPCREATESTRUCT cs = reinterpret_cast<LPCREATESTRUCT>( lParam );
    G::cWin *pWnd = reinterpret_cast<G::cWin*>( cs->lpCreateParams );

    SetLastError( 0 );

    if( !SetWindowLongPtr( hWnd, GWL_USERDATA, reinterpret_cast<LONG_PTR>( pWnd ) ) && GetLastError() ){
        G::Console( L"Error" );
    }
}

G::cWin *G::GetObjectFromHandle( HWND hWnd ){
    return reinterpret_cast<G::cWin*>( GetWindowLongPtr( hWnd, GWL_USERDATA ) );
}

i use visual studio 2005 我使用Visual Studio 2005

You are missing a destructor to destroy your HWND and clean up any references to it. 您缺少销毁您的HWND并清理所有引用的析构函数。 An HWND can be reused after it has been destroyed. HWND销毁后可以重新使用。 If you do not remove a destroyed HWND from your std::map , you will end up with stale cWin* pointers. 如果不从std::map删除被破坏的HWND,则最终将出现陈旧的cWin*指针。

For that matter, your std::map is unnecessary. 因此,您的std::map是不必要的。 You are relying on GetObjectFromHandle() returning a valid cWin* pointer before you access the std::map , but you say GetObjectFromHandle() is not working correctly to begin with. 在访问std::map之前,您依靠的是GetObjectFromHandle()返回有效的cWin*指针,但是您说GetObjectFromHandle() cWin*无法正常工作。 So just get rid of the std::map , you don't need it. 因此,只需摆脱std::map ,就不需要它了。

Try something more like this instead: 尝试类似这样的方法:

.h 。H

#ifndef BASE_WINDOW_H
#define BASE_WINDOW_H

#include "GlobalApp.h"
#include <string>

namespace G
{
    class cWin
    {
    private:
        HWND hWnd;
        LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);

        static LRESULT CALLBACK internal_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

    public:
        cWin();
        ~cWin();

        HWND    getWnd();
        int     registerCls();
        int     createWnd();
    };
}

#endif

.cpp .cpp

#include "stdafx.h"
#include "BaseWindow.h"

G::cWin::cWin()
{
    registerCls();
    createWnd();
    G::Console( L"wndCreated", hWnd );
}

G::cWin::~cWin()
{
    if ( hWnd )
    {
        DestroyWindow( hWnd );
    }
}

HWND G::cWin::getWnd()
{
    return hWnd;
}

int G::cWin::createWnd()
{
    hWnd = ::CreateWindowEx(WS_EX_WINDOWEDGE, L"div", NULL,
        WS_CHILD | WS_VISIBLE,
        50, 50, 50, 50,
        G::hWnd, NULL, G::hInst, this );

    if ( !hWnd )
    {
        G::Console( L"hwnd_ERR" );
        return -1;
    }

    ::UpdateWindow( hWnd );

    return 0;
}

int G::cWin::registerCls()
{
    WNDCLASSEX wcex;

    if ( !::GetClassInfoEx(G::hInst, L"div", &wcex) )
    {
        wcex.cbSize = sizeof(WNDCLASSEX);

        wcex.style          = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc    = &internal_WndProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = DLGWINDOWEXTRA;
        wcex.hInstance      = G::hInst;
        wcex.hIcon          = LoadIcon(G::hInst, MAKEINTRESOURCE(IDI_WINAPITWO));
        wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+3);
        wcex.lpszMenuName   = NULL;
        wcex.lpszClassName  = L"div";
        wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

        if ( !::RegisterClassEx(&wcex) )
        {
            G::Console( L"wcex_ERR" );
            return -1;
        }
    }

    return 0;
}

LRESULT G::cWin::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_LBUTTONDOWN:
            G::Console( L"ButtonDown", hWnd );
            break;

        case WM_DESTROY:
            PostQuitMessage(0);
            break;

        case WM_NCDESTROY:
            this->hWnd = NULL;
            break;

        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }

    return 0;
}

LRESULT CALLBACK G::cWin::internal_WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    G::cWin *pWnd;

    if( uMsg == WM_NCCREATE )
    {
        LPCREATESTRUCT cs = reinterpret_cast<LPCREATESTRUCT>( lParam );
        pWnd = reinterpret_cast<G::cWin*>( cs->lpCreateParams );

        SetLastError( 0 );
        if( !SetWindowLongPtr( hWnd, GWL_USERDATA, reinterpret_cast<LONG_PTR>( pWnd ) ) )
        {
            if( GetLastError() != 0 )
                G::Console( L"Error" );
        }
    }
    else
    {
        pWnd = reinterpret_cast<G::cWin*>( GetWindowLongPtr( hWnd, GWL_USERDATA ) );
    }

    if( pWnd )
    {
        return pWnd->WindowProc( uMsg, wParam, lParam );
    }
    else
    {
        return DefWindowProc( hWnd, uMsg, wParam, lParam );
    }
}

A class' member function is not a part of a class instance. 类的成员函数属于类实例。 You should look at class member functions to work like this: 您应该查看类成员函数,使其工作如下:

class Foo {
};

namespace Foo {
    void Bar(Foo *this, ...);
};

Of course there can not be a namespace on the same scope as a class with the same name. 当然,不能在名称空间与具有相同名称的类相同的作用域内。 This is just for illustration. 这仅用于说明。 When you define a class member function, the compiler translates this into "a function that is placed the namespace of the class definition and has a first implicit parameter this that's set to the pointer of the class instance upon which the function is called with the . or -> operator. static class member functions are merely placed into the class namespace but don't have the implicit this parameter… that's the whole difference. 当您定义类成员函数时,编译器将此转换为“一个函数,该函数位于类定义的名称空间中,并且具有第一个隐式参数, this参数设置为使用调用该函数的类实例的指针.->运算符, static类成员函数仅放置在类名称空间中,但没有隐式this参数……这就是全部。

So in this line 所以在这一行

    wcex.lpfnWndProc    = (WNDPROC)this->internal_WndProc;

the problem is, that there's no instance member "function" variable internal_WndProc. 问题是,没有实例成员“函数”变量internal_WndProc。 You have instead to use just the function from the class namespace: 相反,您只能使用类名称空间中的函数:

    wcex.lpfnWndProc    = G::cWin::internal_WndProc;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM