对winapi窗口进行子类化

时间:2017-06-01 08:57:53

标签: c++ winapi subclass

我正在尝试在Windows(Winapi)上创建一个Window子类。请原谅我缺乏知识,Windows风格的子类化与我从Qt中所知道的不同。

所以我有一个这样的基类窗口(代码摘录自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);

签名现在匹配,不是吗?我不能正确理解错误。我至少走在正确的轨道上了吗?

1 个答案:

答案 0 :(得分:0)

它们并不完全相同。您需要将声明更改为:

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

注意__stdcall