我想在Windows(Winapi)上繼承一個窗口。請原諒我缺乏知識,Windows風格的子類化與我在Qt中所知道的很不一樣。繼承WINAPI窗口
所以我有一個基類窗口像這樣(從deimos1877採取代碼摘錄),這裏是必不可少的一部分:
class BorderlessWindow
{
enum class Style : DWORD
{
windowed = (WS_OVERLAPPEDWINDOW | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CLIPCHILDREN | WS_SYSMENU ),
aero_borderless = (WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CLIPCHILDREN)
};
public:
HWND hWnd;
HINSTANCE hInstance;
BorderlessWindow(HBRUSH windowBackground, const int x, const int y, const int width, const int height);
~BorderlessWindow();
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
};
源文件的一部分:
HWND winId = 0;
BorderlessWindow::BorderlessWindow(HBRUSH windowBackground, const int x, const int y, const int width, const int height)
: hWnd(0),
hInstance(GetModuleHandle(NULL)),
borderless(false),
borderlessResizeable(true),
aeroShadow(false),
closed(false),
visible(false)
{
WNDCLASSEX wcx = { 0 };
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.hInstance = hInstance;
wcx.lpfnWndProc = WndProc;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.lpszClassName = L"WindowClass";
wcx.hbrBackground = windowBackground;
wcx.hCursor = LoadCursor(hInstance, IDC_ARROW);
RegisterClassEx(&wcx);
if (FAILED(RegisterClassEx(&wcx))) {
throw std::runtime_error("Couldn't register window class");
}
hWnd = CreateWindow(L"WindowClass", L"Updater", static_cast<DWORD>(Style::windowed), x, y, width, height, 0, 0, hInstance, nullptr);
if (!hWnd){
throw std::runtime_error("Couldn't create window because of reasons");
}
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
show();
}
LRESULT CALLBACK BorderlessWindow::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
std::cout<<"BorderlessWindow::WndProc"<<std::endl;
BorderlessWindow *window = reinterpret_cast<BorderlessWindow*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
if (!window) return DefWindowProc(hWnd, message, wParam, lParam);
switch (message) {
// ...
}
return DefWindowProc(hWnd, message, wParam, lParam);
在第一所有來自子類的代碼都是BorderlessWindow類中的第一個。本質上,我將一些圖像和文本繪製到窗口中。在我的第一個子類嘗試中(這裏沒有顯示),我沒有照顧WndProc,我認爲這就是圖像和文本不再被繪製的原因。因此,這裏是我的最後一次嘗試:
class Dialog : public BorderlessWindow
{
public:
explicit Dialog();
~Dialog() = default;
void updateTitlebar(HWND hwndParent);
void updateImage(HWND hwndParent);
void updateText(HWND hwndParent);
void setupContent(HWND hwndParent);
protected:
static LRESULT DialogWndProc(HWND hWnd, UINT msg, WPARAM w, LPARAM l, UINT_PTR uid, DWORD_PTR RefData){
std::cout << "Dialog::SubclassWndProc" << std::endl;
Dialog *dlg = reinterpret_cast<Dialog*>(RefData);
if (!dlg){
return DefSubclassProc(hWnd, msg, w, l);
}
switch (msg) {
case WM_PAINT:{
dlg->updateTitlebar(hWnd);
dlg->updateText(hWnd);
dlg->updateImage(hWnd);
break;
}
default:
return DefSubclassProc(hWnd, msg, w, l);
}
}
};
請注意,我換了新的WndProc的簽名包含參數UINT_PTR uid
,因爲最初我得到這個錯誤:
invalid conversion from
'LRESULT (*)(HWND, UINT, WPARAM, LPARAM, DWORD_PTR)
{aka long int (*)
(HWND__*, unsigned int, unsigned int, long int, long unsigned int)}' to
'SUBCLASSPROC
{aka long int (__attribute__((__stdcall__)) *)
(HWND__*, unsigned int, unsigned int, long int, unsigned int, long unsigned int)}' [-fpermissive]
SetWindowSubclass(hWnd,DialogWndProc,0,(DWORD_PTR)this);
添加參數後,根據頭部commctrl.h
typedef LRESULT (CALLBACK *SUBCLASSPROC)(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam,UINT_PTR uIdSubclass,DWORD_PTR dwRefData);
WINBOOL WINAPI SetWindowSubclass(HWND hWnd,SUBCLASSPROC pfnSubclass,UINT_PTR uIdSubclass,DWORD_PTR dwRefData);
它仍然不編譯,示出如下錯誤:
invalid conversion from
'LRESULT (*)(HWND, UINT, WPARAM, LPARAM, UINT_PTR, DWORD_PTR)
{aka long int (*)
(HWND__*, unsigned int, unsigned int, long int, unsigned int, long unsigned int)}' to '
SUBCLASSPROC
{aka long int (__attribute__((__stdcall__)) *)
(HWND__*, unsigned int, unsigned int, long int, unsigned int, long unsigned int)}' [-fpermissive]
SetWindowSubclass(hWnd,DialogWndProc,NULL,(DWORD_PTR)this);
簽名現在正在匹配,不是嗎?我不明白錯誤。我至少在正確的軌道上?
Windows是一個'C' API和不能調用非靜態成員函數。你的回調需要是頂層'C'函數或靜態成員函數。 'BorderlessWindow :: WndProc'是一個非靜態成員函數。 –
該錯誤非常清楚地描述了缺少的內容。調用約定。我恭敬地建議你學習閱讀錯誤信息。編譯器不會發出它們來騷擾你。它發出它們來通知你。被告知。 –
@DavidHeffernan即使如此,我想知道'wcx.lpfnWndProc = WndProc'是如何編譯的,我認爲它會成爲正在出現的問題的根源。 –