问题描述
关于
我正在尝试使用 MFC > Win32 API 。我打算将它包装到类
中。我的第一种方法没有成功。
整个代码
About
I am trying to make an alternative to the MFC
, using the Win32 API
. Which is I am going to wrap it into classes
. My first approach was not succeeded.
The Whole Code
#include <Windows.h>
#include <tchar.h>
/** BASE WINDOW CLASS | AS A TEMPLATE **/
class CWnd
{
public:
virtual void Init(HINSTANCE hInstance) //Registers, Creates, Shows the Window
{
HWND hwnd ;
WNDCLASS wndclass ;
wndclass.style = 0 ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = L"CWndMy32" ;
RegisterClass (&wndclass);
hwnd = CreateWindow (L"CWndMy32", TEXT ("The Hello Program"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,hInstance,
(LPVOID)this) ;
//attach a pointer of the
// class (Cwnd *) to the //window using the last parameter
// of CreateWindow
ShowWindow (hwnd, SW_SHOWNORMAL) ;
UpdateWindow (hwnd) ;
}
protected:
HINSTANCE hInst;
HWND m_hwnd;
private:
//Window Procedure for all of the windows (derived classes like the one below) created by this TEMPLATE CLASS
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
CWnd * _this = (CWnd *) GetWindowLong(hwnd, GWL_USERDATA);
if(msg == WM_NCCREATE)
{
_this = new CWnd;
_this->hInst = GetModuleHandle(0);
_this->m_hwnd = hwnd;
SetWindowLong(hwnd, GWL_USERDATA, (LONG) _this);
return TRUE;
}
return _this->VirtualProc(hwnd, msg, wParam, lParam);
}
//Virtual Procedure Function to override in derived classes
virtual LRESULT VirtualProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
lParam)
{
return DefWindowProc(hwnd, msg, wParam, lParam);
}
};
/** A CLASS FOR USING THE TEMPLATE CLASS | WHICH IS CWnd **/
class CMyWnd : public CWnd
{
private:
//This virtual function Overides the 'VirtualProc' function of the 'CWnd' Class
LRESULT VirtualProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if(msg == WM_LBUTTONDOWN)
MessageBox(0, 0, 0, 0); //To Test if it words, if so, an empty message box will appear when the window is clicked
return DefWindowProc(hwnd, msg, wParam, lParam);
}
};
/** Windows Entry **/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int nCmdShow)
{
CMyWnd wnd; //Object of the Template Used Class | CMyWnd : public CWnd
wnd.Init(hInstance);
MSG msg;
while(GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
我做了什么
1.创建了一个 Base
Class Called'' CWnd
''(我还称之为 TEMPLATE CLASS
)
2.在 CWnd :: Init
;注册,创建并显示窗口。
(在CreateWindow调用中,我附加了一个指针
的 CWnd
到
窗口,因此 CWnd
的每个派生类都有不同的数据,
但是相同的静态
窗口程序)
3. CWnd :: WndProc
是静态
窗口程序。
4. CWnd :: VirtualProc
是虚拟
窗口过程,它被覆盖在派生
班。
5.使用 TEMPLATE CLASS
创建一个派生类,称为'' CMyWnd
''。
6. CMyWnd :: VirtualProc
是覆盖的功能CWnd :: VirtualProc
。
问题
代码可以编译而没有错误,窗口创建得很好。但问题是, CWnd :: VirtualProc
虚拟函数未正确覆盖
CMyWnd :: VirtualProc
。
任何帮助?请?
What I Did
1. Created a Base
Class Called ''CWnd
'' (also I call it the TEMPLATE CLASS
)
2. In CWnd::Init
;Registered, Created and Showed the window.
(In the CreateWindow call, I Attached a pointer
of the CWnd
to
the window, So that every derived class of CWnd
will have different data,
but a same static
window procedure )
3. CWnd::WndProc
is the Static
window procedure.
4. CWnd::VirtualProc
is the Virtual
window procedure which is overridden in derived
classes.
5. Created a Derived class using TEMPLATE CLASS
, called ''CMyWnd
''.
6. CMyWnd::VirtualProc
is the function that overrode CWnd::VirtualProc
.
The Problem
Code can be compiled with no errors, and the window is created nicely. But the problem is that, CWnd::VirtualProc
virtual function is not correctly overrode withCMyWnd::VirtualProc
.
Any Help ?? Please ?
推荐答案
_this = new CWnd;
请参阅下面的更正代码...还有其他一些小问题。
为了避免这样的错误, CWnd类摘要。这种方式直接创建CWnd会导致编译错误。你可以这样做,例如为它创建一个具有受保护可见性的空构造函数!
我觉得奇怪的是你的虚函数在基类中是私有的,你应该把它至少保护。在派生类中,使用virtual标记重写方法是一个很好的做法,即使它不是必需的,因为它对于阅读代码的人来说是一个很好的文档,而visual C ++有一个非常好的覆盖关键字,你可以在之后编写函数声明(就地,或'const''关键字之后)如果函数实际上没有覆盖基类方法,它会导致编译失败(例如,因为有人在更改基类方法签名期间重构...)。所以msvc中的override关键字也是测试问题的好方法!
关于你的代码的一些其他注释:
通过WM_NCCREATE挂钩是非常好的,尽管我很少看到它,这是挂钩的正确方法。在你的实现中,WM_NCCREATE没有传递给虚拟wndproc,但这是一个实现细节,类中很少需要WM_NCCREATE,通常WM_CREATE就足够了。如果你考虑使用64位,那么你应该使用SetWindowLongPtr和GWLP_USERDATA而不是SetWindowLong + GWL_USERDATA。虚拟wndproc通常在窗口消息上包含一个大开关,我通常喜欢这样写:
See the corrected code below... And there are some other minor issues too.
To avoid such bugs make the CWnd class abstract. This way creating CWnd directly causes compile error. You can do this for example by creating an empty constructor for it with protected visibility!
Something that seems strange to me is that your virtual function is private in the base class, you should put it to at least protected. In the derived class its a good practice to mark the overridden method with virtual even if its not required because its a good documentation for people who read the code, and visual C++ has a very nice ''override'' keyword that you can write after the function declaration (in place, or after the ''const'' keyword) and it causes the compilation to fail if the function doesn''t actually override a base class method (for example because someone has changed the base class method signature during refactor...). So the override keyword in msvc is a nice way to test for your problem as well!
A few other notes regarding your code:
The hooking via WM_NCCREATE is very nice, it is the correct way to do the hooking despite the fact that I see it rarely. In your implementation WM_NCCREATE isn''t passed to the virtual wndproc but that is an implementation detail, WM_NCCREATE is rarely needed inside the class, usually WM_CREATE is enough. If you consider going to 64 bit then you should use SetWindowLongPtr with GWLP_USERDATA instead of SetWindowLong+GWL_USERDATA. The Virtual wndproc usually contains a big switch on the window message and I usually like writing it this way:
//-------- In the derived class:
struct SWndMsg
{
HWND hwnd; // hwnd is optional because the m_hwnd member is always available
UINT msg;
WPARAM wParam;
LPARAM lParam;
}
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if(msg == WM_NCCREATE)
{
CWnd * _this = (CWnd*)((CREATESTRUCT*)lParam)->lpCreateParams; // !!!!!!!!!!! your bug
_this->hInst = GetModuleHandle(0);
_this->m_hwnd = hwnd;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)_this);
}
CWnd * _this = (CWnd *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
SWndMsg m;
m.hwnd = hwnd;
m.msg = msg;
m.wParam = wParam;
m.lParam = lParam;
return _this->VirtualProc(m);
}
// A method in the base class that you can use with the SWndMsg struct
// instead of DefWindowProc()
LRESULT Default(SWndMsg& msg)
{
return DefWindowProc(msg.hwnd, msg.msg, msg.wParam, msg.lParam);
}
//-------- In the derived class:
// Here comes the 'override' keyword...
virtual LRESULT VirtualProc(SWndMsg& msg) override
{
switch (msg)
{
case WM_LBUTTONDOWN:
// Its easier to split the code into multiple functions if you
// pass just 1 parameter instead of 4 and it looks nicer...
return OnWMLButtonDown(msg);
case WM_COMMAND:
return OnWMCommand(msg);
...
default:
return Default(msg);
}
}
void OnWMLButtonDown(SWndMsg& msg)
{
if (blahblah)
{
...
}
else
{
// The Default() method can come handy in a lot of message specific methods...
return Default(msg);
}
}
代码可能包含错误,因为我在浏览器中写了它并没有编译它!
The code might contain bugs as I wrote it in the browser and havent compiled it!
这篇关于窗口过程作为类内的虚函数。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!