调用CallWindowProc函数时,显示无法访问m_OldProc,经过测试发现其存储的值,与Init内存储的不同,但是找不到是哪里更改了。
更新:问题已解决,保存文章,作为警示。
解决过程:把传入的对象由直接申请改为new分配内存,即可正常运行。
原因:原对象是局部变量,WM_CREATE消息处理完成后,函数结束变量被释放,导致函数地址丢失。所以在按钮处理WM_PAINT消息时,变量已被释放,从m_OldProc获取到的是随机值,故而导致CallWindowProc出现访存错误。果然这就是C++基础没打好的后果...
BaseButton.h
#pragma once
#include<windows.h>
class BaseButton {
public:
BOOL SetBackPic(HBITMAP hBitmap, BOOL bReSize);
BOOL Init(HWND hWnd);
BaseButton();
virtual ~BaseButton();
static LRESULT WINAPI newProc(HWND hWnd, UINT uMsg, UINT wParam, LONG lParam);
LRESULT CALLBACK WndProc(UINT message, WPARAM wParam, LPARAM lParam);
private:
LRESULT OnPaint(HDC hdc);
HWND m_hwnd;//当前的BUTTON句柄
HWND m_parent_hwnd;//当前BUTTON的父窗口的句柄
LONG m_OldProc;//原来的回调函数地址
HBITMAP hBackPic;
};
BaseButton.cpp
#include "BaseButton.h"
BaseButton::BaseButton() {}
BaseButton::~BaseButton() {}
BOOL BaseButton::Init(HWND hwnd) {
//IsWindow函数不应被用于其他线程创建的窗口,因为在函数调用后该窗口可能被销毁,或者句柄指向不同窗口(两个线程同时运行)
if (IsWindow(hwnd)) {
m_hwnd = hwnd;//托管原来的BUTTON
m_parent_hwnd = GetParent(m_hwnd);
//setProp给m_hwnd句柄对应窗口的属性列表添加一个条目(存在则修改条目,不存在则添加条目,本处为添加),添加失败返回0,否则非0
if (SetProp(m_hwnd, "BaseButton", (HANDLE)this) == 0) {
return FALSE;
}
//改变窗口回调过程
m_OldProc = SetWindowLongPtr(m_hwnd, GWL_WNDPROC, (LONG)newProc);
}
return FALSE;
}
LRESULT WINAPI BaseButton::newProc(HWND hwnd, UINT uMsg, UINT wParam, LONG lParam) {
BaseButton* bp = (BaseButton*)GetProp(hwnd, "BaseButton");
return bp->WndProc(uMsg, wParam, lParam);
}
//改变原BUTTON的回调过程
LRESULT CALLBACK BaseButton::WndProc(UINT message, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC hdc;
switch (message) {
//调用自己设定的刷新
case WM_PAINT: {
hdc = BeginPaint(m_hwnd, &ps);
OnPaint(hdc);
EndPaint(m_hwnd, &ps);
break;
}
}
//默认回调过程
//m_OldProc = 0x77eb7a80;
return CallWindowProc((WNDPROC)m_OldProc, m_hwnd, message, wParam, lParam);
}
//在这里添加BUTTON的背景设置
LRESULT BaseButton::OnPaint(HDC hdc) {
HDC hdcMem, hdcBmp;
RECT rt;
int width, height;
HBITMAP bmp;
SetBkMode(hdc, TRANSPARENT);
GetClientRect(m_hwnd, &rt);
width = rt.right - rt.left;
height = rt.bottom - rt.top;
hdcMem = CreateCompatibleDC(hdc);
hdcBmp = CreateCompatibleDC(hdc);
SetBkMode(hdcMem, TRANSPARENT);
bmp = CreateCompatibleBitmap(hdc, width, height);
SelectObject(hdcMem, bmp);
if (hBackPic != NULL)
{
SelectObject(hdcBmp, hBackPic);
}
BitBlt(hdcMem, 0, 0, width, height, hdcBmp, 0, 0, SRCCOPY);
BitBlt(hdc, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY);
DeleteDC(hdcBmp);
DeleteDC(hdcMem);
DeleteObject(bmp);
return TRUE;
}
BOOL BaseButton::SetBackPic(HBITMAP hBitmap, BOOL bReSize)
{
BITMAP bm;
RECT rt;
hBackPic = hBitmap;
if (hBitmap != NULL)
{
if (bReSize)
{
GetObject(hBackPic, sizeof(bm), &bm);
SetWindowPos(m_hwnd, 0, 0, 0, bm.bmWidth, bm.bmHeight, SWP_NOMOVE | SWP_NOREPOSITION);
}
GetClientRect(m_hwnd, &rt);
InvalidateRect(m_hwnd, &rt, TRUE);
return TRUE;
}
return FALSE;
}
MultifunctionalCalculator.cpp
// MultifunctionalCalculator.cpp : 定义应用程序的入口点。
//
#include <windows.h>
#include "framework.h"
#include "MultifunctionalCalculator.h"
#include "layoutSave.h"
#include "BaseButton.h"
int APIENTRY WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
_In_ PSTR szCmdLine, _In_ int iCmdShow);
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
LayoutSave* initLayoutSave();
int APIENTRY WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
_In_ PSTR szCmdLine, _In_ int iCmdShow)
{
static TCHAR szAppName[] = TEXT("计算器");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
//wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MULTIFUNCTIONALCALCULATOR));
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("创建窗口失败!"),
szAppName, MB_ICONERROR);
return 0;
}
int iDefaultX = 510, iDefaulty = 220;
int iMinWindowWidth = 340, iMinWindowHeight = 510;
hwnd = CreateWindow(szAppName, TEXT("计算器"),
WS_OVERLAPPEDWINDOW,
iDefaultX, iDefaulty, iMinWindowWidth, iMinWindowHeight,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
//窗口过程
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LayoutSave* standardLayout = initLayoutSave();
HDC hdc;
PAINTSTRUCT ps;
HWND hwndButtonList[100];
//BaseButton changeButton;错误代码
static BaseButton *changeButton = new BaseButton;
switch (message) {
case WM_CREATE: {
hwndButtonList[0] = CreateWindow(TEXT("BUTTON"), TEXT("BUTTON1"), WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, hwnd, 0, (HINSTANCE)lParam, NULL);
changeButton.Init(hwndButtonList[0]);
return 0;
}
case WM_PAINT: {
hdc = BeginPaint(hwnd,&ps);
EndPaint(hwnd, &ps);
break;
}
case WM_DESTROY: {
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
LayoutSave* initLayoutSave() {
LayoutSave* standardLayout = nullptr;
int* standardWidth = new int[7]{ 50,77,77,77,77,77,77 };
int* standardHeight = new int[7]{ 30,47,47,47,47,47,47 };
standardLayout = new LayoutSave(10,175,7,standardWidth, standardHeight);
return standardLayout;
}