在窗口过程包装器

时间:2017-06-26 14:09:49

标签: c++ winapi

我正在编写一个windows api包装器库。但我遇到了问题:每当我尝试在“包装”窗口过程中使用this指针时,就会抛出读取访问冲突 - 从静态版本调用的过程。这是库接口

class widget {
protected:
    HWND hwnd;
public: // instinfo is class that represents WNDCLASS structure
    widget(instinfo ii, const WCHAR *text,
        DWORD styles = WS_OVERLAPPEDWINDOW,
        point ul = DEFUL,
        int cx = CW_USEDEFAULT,
        int cy = CW_USEDEFAULT,
        HWND parent = NULL,
        HMENU hm = NULL);
};

class olwindow : public widget {
    // static window proc: It registered by WNDCLASS structure
    static LRESULT CALLBACK baseWinProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp);
    LRESULT CALLBACK winproc(UINT wm, WPARAM wp, LPARAM lp);
protected:
    virtual void LButtonDown(int, int) { } // an example event, is override by classes that inherit and wanna customize
public:
    friend class instinfo;

    olwindow(instinfo ii, const WCHAR *cap, point ul = DEFUL, 
        int cx = CW_USEDEFAULT, int cy = CW_USEDEFAULT);
};

相关功能为baseWinProcwinproc,我将在下面显示:

LRESULT olwindow::baseWinProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp)
{
    olwindow *w;

    if (wm == WM_NCCREATE)
        SetWindowLong(hwnd, GWL_USERDATA, (LONG) ((CREATESTRUCT *) lp)->lpCreateParams);

    w = (olwindow *) GetWindowLong(hwnd, GWL_USERDATA);
    if (w)
        w->winproc(wm, wp, lp);
    return DefWindowProc(hwnd, wm, wp, lp);
}

LRESULT olwindow::winproc(UINT wm, WPARAM wp, LPARAM lp)
{
    switch (wm) {
        case WM_LBUTTONDOWN:
            // on line below is crash
            this->LButtonDown(GET_X_LPARAM(lp), GET_Y_LPARAM(lp));
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
    }
    return 0;
}

错误消息是

  

抛出异常:读取访问冲突。

     

这 - >是0x12A07E0。

这意味着什么?

编辑:这是widget类的构造函数,它由olwindow的构造函数调用

widget::widget(instinfo ii, const WCHAR * text, DWORD styles, point ul, 
         int cx, int cy, HWND parent, HMENU hm)
{
    this->hwnd = CreateWindow(ii.getClassName(), text, styles, 
         ul.x, ul.y, cx, cy, parent, hm, ii.getHinst(), this);
    if (this->hwnd == NULL)
        MessageBox(NULL, getErrMsg(), L"", 0);
    ShowWindow(this->hwnd, SW_SHOW);
}

olwindow::olwindow(instinfo ii, const WCHAR * cap, point ul, int cx, int cy) :
    widget(ii, cap, WS_OVERLAPPEDWINDOW, ul, cx, cy)
{ }

1 个答案:

答案 0 :(得分:1)

问题是由两个因素共同造成的:

  • 派生类型的构造顺序。
  • 事实上,CreateWindow在返回之前向窗口过程发送了许多消息。从文档:
      

    在返回之前,CreateWindow会向窗口过程发送WM_CREATE消息。对于重叠,弹出窗口和子窗口,CreateWindow会向窗口发送WM_CREATE,WM_GETMINMAXINFOWM_NCCREATE消息。

由于CreateWindow在基类(widget)构造函数中执行,因此派生类' olwindow消息处理程序运行时,尚未构造(WM_NCCREATE)实例。将通过CREATESTRUCT传递的指针转换为派生类'因此,类型是一个错误。

要解决此问题,您需要将指针强制转换为其原始类型,即widget*。如果需要在窗口过程中访问派生对象,则需要将窗口创建移动到完全构造它的位置。

作为替代方案,您可以继续从基类构造函数中调用CreateWindow,但只有在完全构造后才转换为派生对象,例如:通过在派生类的基类中存储一个布尔值'构造