我正在为D编写一个面向对象的窗口API包装器,我有一个(非语言特定的)设计问题。
Windows要求所有窗口都先前已注册RegisterClass
;扩展现有类需要替换窗口过程。此外,似乎有两种窗口句柄:HWND
s需要处理(通过DestroyWindow
),而HWND
s则不处理(例如来自其他应用程序)。
我创建了一个Window
类,只要我只是包装ShowWindow
,UpdateWindow
,FindWindow
和其他类似的方法,一切都很好和花花公子。但是当我尝试向我的调用className
的类添加一个带有CreateWindow
参数的构造函数时,我遇到了一个问题:
className
必须已经注册了给定的RegisterClass
。Window
的子类以某种方式调用RegisterClass
。Window
子类,所有实例实际上都是同一窗口类的实例;即,来自特定子类的所有className
都是相同的。 (这是因为特定窗口类的所有实例的窗口过程必须相同。)问题是,没有办法让abstract static
方法(为了让Window能够向子类询问他们的类信息,并将它们注册一次),所以我不得不说像CreateWindow(this.className, ...)
这样的东西,以便创建一个新的窗口,如果我的子类不遵守这个规则,这很容易成为问题,并为每个窗口实例提供一个不同的类名。
此外,我需要WNDCLASS.lpfnWndProc
字段和我的Window子类(重写)WndProc
方法之间的一对一映射。但是,如果我被迫在每个实例的基础上获取方法指针,那么这并不完全有效,因为它打破了整个OOP设计并使一切都搞砸了。
虽然我可以在运行时强制执行这种一致性,但它有点难看,因此它不是一个很好的解决方案。
所以,长话短说,有没有人知道创建abstract static
方法问题的优雅解决方案?我正在考虑一些像Factory和whatnot这样的设计模式,但我不确定它们是否适合这里......如果有人认为它们可能,我会非常感谢它对它如何适合设计的一点解释。
谢谢!
答案 0 :(得分:2)
此标准解决方案是为基类提供两个窗口过程a static one and a virtual one。
基类使用静态窗口过程注册其类。然后,静态窗口过程调用虚拟窗口过程。许多人省略了虚拟版本中的HWND
参数,因为它可以从this
指针获取,但我会将其保留以简化故事。
class Window
{
public:
virtual LRESULT WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ return DefWindowProc(hwnd, uMsg, wParam, lParam); }
private:
static LRESULT CALLBACK StaticWndProc(
HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_NCCCREATE) {
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(
reinterpret_cast<LPCREATESTRUCT>(lParam)->lpCreateParams);
}
Window *pThis = reinterpret_cast<Window*>(
GetWindowLongPtr(hwnd, GWLP_USERDATA));
LRESULT lres = pThis ? pThis->WndProc(hwnd, uMsg, wParam, lParam)
: DefWindowProc(hwnd, uMsg, wParam, lParam);
}
};
派生类覆盖Window::WndProc
。
答案 1 :(得分:0)
对于特定类名的所有实例,窗口proc不必相同。
通常,您使用RegisterClass
函数为该类的窗口设置默认窗口proc。当您创建一个使用该类但又希望它覆盖默认处理的新窗口时,您创建窗口然后调用SetWindowLongPtr(hwnd, GWL_WNDPROC, newWndProc)
,其中newWndProc
是指向新窗口窗口proc的指针。< / p>
新窗口的窗口proc然后可以处理它想要覆盖的消息,并为其余部分调用DefWindowProc
。
要构造具有新类名的窗口,请让构造函数复制继承类的类信息,并创建一个与该名称相同的新类,但名称除外。然后公开一个允许客户端更改特定于类的事物的方法。您感兴趣的API函数包括GetClassInfoEx
和SetClassLong
,SetClassWord
或SetClassLongPtr
。
继承在这个世界中仍然有意义,因为默认处理对于特定类的每个窗口都是相同的,并且继承的类继承了父项的默认处理。
为此,您不需要abstract static
方法。您只需要窗户把手。您可以通过使用窗口句柄调用GetClassName
来获取类名,然后使用返回的类名称调用GetClassInfoEx
。
答案 2 :(得分:0)
我在Google上搜索了x86 thunks
这个词组。而且,事实证明,我不是第一个遇到这个问题的人(出乎意料!)。
关于Window Procs的第一个问题就是这个问题的exact problem and the solution,尽管它与我的查询没有任何关系(或者至少,很少直接做)...希望其他人发现它有用太