MDI 面向对象方法,从 MDICREATESTRUCT 中检索此指针 [英] MDI object oriented approach, retrieving this pointer from MDICREATESTRUCT
问题描述
我正在尝试实现 MDI 子窗口基类,根据 到此参考 备注的详细信息说
I'm trying to implement MDI Child window base class, according to this reference details on remarks say
当 MDI 客户端窗口通过调用创建 MDI 子窗口时CreateWindow,系统向创建的窗口发送 WM_CREATE 消息窗户.WM_CREATE 消息的 lParam 成员包含一个指针到 CREATESTRUCT 结构.这个 lpCreateParams 成员结构包含指向传递的 MDICREATESTRUCT 结构的指针使用创建 MDI 子窗口的 WM_MDICREATE 消息.
When the MDI client window creates an MDI child window by calling CreateWindow, the system sends a WM_CREATE message to the created window. The lParam member of the WM_CREATE message contains a pointer to a CREATESTRUCT structure. The lpCreateParams member of this structure contains a pointer to the MDICREATESTRUCT structure passed with the WM_MDICREATE message that created the MDI child window.
我使用以下简单的基模板类来创建 MDI 子窗口,实现上述语句来检索此指针.(添加了一些评论)
I'm using following simple base template class to create MDI child window, implementing above statements to retrieve this pointer. (added few comments)
basemdi.h
#pragma once
#include <Windows.h>
template <typename DERIVED_TYPE>
class BaseMDI
{
public:
inline HWND GetHandle() const;
BOOL Initialize(
PCTSTR szWindowName,
HWND hParent,
DWORD dwExStyle = WS_EX_MDICHILD, // THIS IS MDI WINDOW
DWORD dwStyle = 0,
int x = CW_USEDEFAULT,
int y = CW_USEDEFAULT,
int width = CW_USEDEFAULT,
int height = CW_USEDEFAULT,
HMENU hMenu = nullptr,
HINSTANCE hInstance = GetModuleHandle(nullptr),
LPVOID lpCreate = nullptr
);
protected:
virtual PCTSTR ClassName() const = 0;
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) = 0;
HWND m_hwnd = nullptr;
};
template<typename DERIVED_TYPE>
BOOL BaseMDI<DERIVED_TYPE>::Initialize(
PCTSTR szWindowName,
HWND hParent,
DWORD dwExStyle,
DWORD dwStyle,
int x,
int y,
int width,
int height,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpCreate)
{
UNREFERENCED_PARAMETER(lpCreate);
WNDCLASSEX wc = { };
wc.cbClsExtra = 0;
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbWndExtra = 0;
wc.hbrBackground = reinterpret_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hIcon = nullptr;
wc.hInstance = hInstance;
wc.lpfnWndProc = WindowProc;
wc.lpszClassName = ClassName();
wc.lpszMenuName = nullptr;
wc.style = CS_VREDRAW | CS_HREDRAW;
RegisterClassEx(&wc);
MDICREATESTRUCT mdicreate;
// ASSIGN POINTER TO THIS SO THAT WE LATER RETRIEVE IT
mdicreate.lParam = (LPARAM) this;
mdicreate.szClass = ClassName();
mdicreate.szTitle = TEXT("Hello");
mdicreate.hOwner = hInstance;
mdicreate.x = CW_USEDEFAULT;
mdicreate.y = CW_USEDEFAULT;
mdicreate.cx = CW_USEDEFAULT;
mdicreate.cy = CW_USEDEFAULT;
mdicreate.style = dwStyle;
m_hwnd = CreateWindowEx(
dwExStyle,
ClassName(),
szWindowName,
dwStyle,
x, y,
width,
height,
hParent,
hMenu,
hInstance,
&mdicreate // PASS ADDRESS OF MDICREATESTRUCT
);
return m_hwnd ? TRUE : FALSE;
}
// following base class WndProc calls derived class procedure,
// I retrive this pointer here to call correct procedure, but pThis is read acess vioalaiton
template<typename DERIVED_TYPE>
inline LRESULT BaseMDI<DERIVED_TYPE>::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
DERIVED_TYPE* pThis = nullptr;
if (uMsg == WM_CREATE)
{
// RETRIEVE POINTER TO THIS
CREATESTRUCT* pCreate = reinterpret_cast<CREATESTRUCT*>(lParam);
MDICREATESTRUCT* pMdi = reinterpret_cast<MDICREATESTRUCT*>(pCreate->lpCreateParams);
pThis = reinterpret_cast<DERIVED_TYPE*>(pMdi->lParam);
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));
pThis->m_hwnd = hWnd;
}
else
{
pThis = reinterpret_cast<DERIVED_TYPE*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
}
if (pThis)
{
// EXCEPTION IS THROWN HERE
return pThis->HandleMessage(uMsg, wParam, lParam);
}
else
{
return DefMDIChildProc(hWnd, uMsg, wParam, lParam);
}
}
template <typename DERIVED_TYPE>
HWND BaseMDI<DERIVED_TYPE>::GetHandle() const
{
return m_hwnd;
}
这是我创建 MDI 子窗口对象的实际实例的方法,该类继承上述模板化基类
Here is how I create an actual instance of the MDI child window object, the class inherits above templated base class
mdiwindow.h
#pragma once
#include "mdibase.h"
class MDI : public BaseMDI<MDI>
{
public:
virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) override;
private:
inline virtual PCTSTR ClassName() const override;
};
PCTSTR MDI::ClassName() const
{
return TEXT("MDIWindow");
}
mdiwindow.cpp
#include "mdiwindow.h"
LRESULT MDI::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
default:
return DefMDIChildProc(m_hwnd, uMsg, wParam, lParam);
}
}
创建 MDI 子级时,我在 basemdi.h 中遇到异常,提示 pThis 指针读取访问冲突.
When the MDI child is created I got exception in basemdi.h saying read access violation for pThis pointer.
我正在遵循 msdn 说明,了解如何检索指向 MDICREATESTRUCT
的指针,该指针传递给 CreateWindowEx
,该指针在 this
中保存了指向 this
的指针code>lpCreateParams 但由于某种原因检索到的指针不起作用.
I'm folowing msdn instructions on how to retrieve pointer to MDICREATESTRUCT
that is passed to CreateWindowEx
, which holds pointer to this
in lpCreateParams
but for some reason the retrieved pointer doesn't work.
你知道这是什么原因吗?
Do you see what could be cause for this?
推荐答案
我最近在使用带有 OOP 方法的 MDI 来获得乐趣,这对我有用:
I was recently using MDI with an OOP approach for fun and this works for me:
MDICREATESTRUCT mcs;
mcs.szTitle = WindowText();
mcs.szClass = ClassName();
mcs.hOwner = GetModuleHandle( nullptr );
mcs.x = x;
mcs.y = y;
mcs.cx = width;
mcs.cy = height;
mcs.style = dwStyle;
mcs.lParam = reinterpret_cast< LPARAM >( this );
mSubWnd = reinterpret_cast< HWND >( SendMessage( hParent, WM_MDICREATE, 0, reinterpret_cast< LONG >( &mcs ) ) );
这篇关于MDI 面向对象方法,从 MDICREATESTRUCT 中检索此指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!