cpp WinAPI WndProc封装在类中
cpp WinAPI WndProc wrapped in the class
我想创建一个类来动态实例化窗口,但由于几周后无法正常工作,将非常感谢您的帮助
由于我无法使用GetObjectFromHandle函数检索正确的数据,我尝试使用std::map来存储类实例,在构造函数中,我可以按预期访问映射中的数据,但在HWND-HWND正确的情况下,从消息循环中,我只能访问垃圾。
这是代码
.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
和.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 ) );
}
我使用visual studio 2005
您缺少一个析构函数来销毁HWND
并清除对它的任何引用。HWND
在销毁后可以重用。如果您不从std::map
中删除已销毁的HWND,那么您最终将得到过时的cWin*
指针。
就这一点而言,您的std::map
是不必要的。在访问std::map
之前,您依赖于GetObjectFromHandle()
返回一个有效的cWin*
指针,但您认为GetObjectFromHandle()
一开始工作不正常。所以只要去掉std::map
,你就不需要它了
试试类似的东西:
.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
#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 );
}
}
类的成员函数不是类实例的一部分。您应该看看类成员函数的工作方式:
class Foo {
};
namespace Foo {
void Bar(Foo *this, ...);
};
当然,命名空间不可能与具有相同名称的类在同一范围内。这只是为了举例说明。定义类成员函数时,编译器将其翻译为"一个放置在类定义的命名空间中的函数,它有一个第一个隐式参数this
,该参数设置为用.
或->
运算符调用该函数的类实例的指针。static
类成员函数只放置在类命名空间中,但没有隐式this
参数……这就是全部区别。
所以在这条线上
wcex.lpfnWndProc = (WNDPROC)this->internal_WndProc;
问题是,没有实例成员"函数"变量internal_WandProc。您只需要使用类名称空间中的函数:
wcex.lpfnWndProc = G::cWin::internal_WndProc;
相关文章:
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- WinAPI挂钩鼠标
- 将执行、作业和WinAPI相乘
- 将可变参数函数的参数封装在类实例中
- 如何在桌面C++上使用 WinApi 画线
- WINAPI 注册应用程序重新启动时不清除打开的套接字
- Winapi:屏幕截图未显示在窗口中
- 如何封装一个函数,以便它只能由同一类中的一个其他函数调用?
- WinAPI 在单击第一个对话框上的按钮控件并销毁第一个对话框后创建第二个对话框
- 封装C++模板
- Qt with WinAPI MouseProc
- 将 RTOS 队列对象封装在仅具有静态分配的 IQueue 自定义接口中
- 从封装在对象中的函数 C++ 返回时为空的列表
- 如何在"SUBSYSTEM:WINDOWS"下显示并输出到Windows(C++ WinApi)上的
- WinAPI 无法创建按钮
- 将 Win32/WinAPI 应用程序移植到 wxWidgets
- WinAPI 检查窗口是否具有常规标题栏
- 如何使用带有矢量的 winapi 读取进程内存从另一个进程读取缓冲区?
- 当要访问的对象被多次封装时,如何正确使用setter
- cpp WinAPI WndProc封装在类中