2017-06-01 90 views
0

我想在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); 

簽名現在正在匹配,不是嗎?我不明白錯誤。我至少在正確的軌道上?

+0

Windows是一個'C' API和不能調用非靜態成員函數。你的回調需要是頂層'C'函數或靜態成員函數。 'BorderlessWindow :: WndProc'是一個非靜態成員函數。 –

+0

該錯誤非常清楚地描述了缺少的內容。調用約定。我恭敬地建議你學習閱讀錯誤信息。編譯器不會發出它們來騷擾你。它發出它們來通知你。被告知。 –

+0

@DavidHeffernan即使如此,我想知道'wcx.lpfnWndProc = WndProc'是如何編譯的,我認爲它會成爲正在出現的問題的根源。 –

回答

0

它們並不完全相同。您需要聲明更改爲:

static LRESULT __stdcall DialogWndProc(HWND hWnd, UINT msg, 
        WPARAM w, LPARAM l, UINT_PTR uid, DWORD_PTR RefData) 

通知的__stdcall

+0

謝謝。我另外用'WINAPI'替換了'__stdcall'。 – user2366975

+1

@user爲什麼選擇'WINAPI'?該聲明將其定義爲'CALLBACK'。我知道他們通常會擴展到相同的東西,但爲什麼不準確呢? –

+0

我搜索了'__stdcall',發現這個:https://stackoverflow.com/questions/297654/what-is-stdcall。而且因爲我在Windows編程的各處都閱讀了WINAPI,所以我認爲它看起來更像「Windows like」。 – user2366975