封装windows的回调函数
windows的回调函数(CALLBACK)拥有严格的参数表。如果直接封装成类的成员函数,在调用的时候会带有this指针,与回调函数的参数表不一致,导致连编译都过不了。
有两种方式可以将这个this指针去掉:
1、将回调函数声明为静态的成员函数。
2、将回调函数声明为友元friend。
第一种:将回调函数声明为静态的成员函数。
静态的成员函数只能用静态的成员变量,如果将一个类所有成员都声明为静态的,那你为什么要封装? 对象都不用创建。几乎失去了类的大部分功能。
如何用静态成员函数使用非静态的成员?
可以参考这两篇文章
https://blog.csdn.net/jia_xiaoxin/article/details/2887352
https://blog.csdn.net/Arcsinsin/article/details/9771251
第二种:将回调函数声明为友元friend。
原理与上面一样,我就不多说了
代码附上:
Frame.h
#include <Windows.h>
class Frame{
private:
HWND hwnd;
WNDCLASSEX wndclass;
MSG msg;
HINSTANCE hInstance;
int x, y;
int width, height;
public:
Frame(HINSTANCE hInstance, WNDPROC WndProc = NULL);
~Frame();
void start();//在这里面手动调用一次回调函数
void setSize(int, int);//设置窗口大小
void setPos(int, int);//设置窗口的位置
void setVisible(bool);//设置窗口显示与隐藏 同时创建窗口,消息循环
public:
friend LRESULT CALLBACK lpfnWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
};
Frame.cpp
#include "Frame.h"
Frame::Frame(HINSTANCE hInstance, WNDPROC WndProc){
x = 0;
y = 0;
width = 0;
height = 0;
hwnd = NULL;
this->hInstance = hInstance;
if (WndProc == NULL){
wndclass.lpfnWndProc = lpfnWndProc;
}
else{
wndclass.lpfnWndProc = WndProc;
}
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(hInstance, IDC_ARROW);
wndclass.hInstance = hInstance;
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszClassName = L"mywin";
wndclass.lpszMenuName = NULL;
wndclass.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
if (!RegisterClassEx(&wndclass)){
MessageBox(NULL, L"窗口注册失败!", L"提示", MB_OK);
exit(-1);
}
}
Frame::~Frame(){
}
void Frame::setSize(int width, int height){
this->width = width;
this->height = height;
}
void Frame::setPos(int x, int y){
this->x = x;
this->y = y;
}
/*
* 负责创建窗口,将窗口显示或者隐藏
*/
void Frame::setVisible(bool b){
if (hwnd == NULL){
this->start();//只是在创建窗口时调用
hwnd = CreateWindowEx(
NULL, ClassName, L"hello world",
WS_OVERLAPPEDWINDOW,
x, y, width, height,
NULL, NULL, hInstance, NULL);
if (hwnd == NULL){
MessageBox(NULL, L"窗口创建失败!", L"提示", MB_OK);
exit(-1);
}
ShowWindow(hwnd, SW_SHOWDEFAULT);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
if (b){
ShowWindow(hwnd, SW_NORMAL);
}
else if(!b){
ShowWindow(hwnd, SW_HIDE);
}
}
void Frame::start(){
lpfnWndProc(NULL, NULL, NULL, (LPARAM)this);
}
LRESULT CALLBACK lpfnWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
//将对象指针设置为静态,当操作系统调用回调函数时不会改变对象
static Frame *frame;
if (hwnd == NULL){
//第一次调用的时候是手动调用,传递的参数为NULL
frame = (Frame*)lParam;
}
HDC hdc;
PAINTSTRUCT ps;
switch (msg){
case WM_CREATE:
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
//这里就可以直接用对象的私有变量了
Rectangle(hdc, 0, 0, frame->width, frame->height);
EndPaint(hwnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProcA(hwnd, msg, wParam, lParam);
}
test.cpp
#include <Windows.h>
#include "Frame.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, PCHAR iCmdLine, int iCmdShow){
Frame frame(hInstance);
frame.setPos(200, 150);
frame.setSize(800, 400);
frame.setVisible(TRUE);
return 0;
}
编译器:VS2013
环境:windows10
因为学过Java,所以自己设计的时候函数的名字或者代码风格有点有点Java的倾向。然后就是正在学习windows程序设计,所以有什么不对的,欢迎指出。