使用SHAutoComplete对Edit控件进行子类化

时间:2014-12-13 00:06:26

标签: winapi subclassing

我是新人,很抱歉,如果这个问题没有完全按照您的习惯而提出。

我不可避免地需要为这样调用SHAutoComplete()的Edit控件创建子类:

// initialization
if FAILED( CoInitialize(NULL) ) exit(1);
// creation of an Edit control
HWND hEdit=CreateWindow( WC_EDIT, ... );
// calling SHAutoComplete - I essentially understand this as a subclassing behind the scenes
SHAutoComplete( hEdit , SHACF_AUTOSUGGEST_FORCE_ON|SHACF_FILESYSTEM );
// subclassing an Edit box for which SHAutoComplete has been called
WNDPROC autoCompleteWndProc=SubclassWindow( hEdit , __myNewWndProc__ ); // using macro

假设__myNewWndProc__函数看起来像一个经典的窗口过程:

LRESULT CALLBACK __myNewWndProc__(HWND hEdit, UINT msg, WPARAM wParam, LPARAM lParam){
    // handle subclass-specific messages
    switch (msg){ ... }
    // handle SHAutoComplete-specific messages
    return autoCompleteWndProc(hEdit,msg,wParam,lParam); // <-- here's the problem (read further)
}

问题是,它不起作用。应用程序崩溃并出现错误:

  

进程返回-1073741819(0xC0000005)&#34; (访问违规)

将问题指向上面列表中标记的行。

问题是我做错了什么?

(我从ComboBoxEx继承子时遇到了同样的问题,但我设法解决了这个问题,但找不到SHAutoComplete()问题的任何技巧。)

1 个答案:

答案 0 :(得分:2)

SubclassWindow()SetWindowLongPtr()的包装器:

#define     SubclassWindow(hwnd, lpfn)       \
              ((WNDPROC)SetWindowLongPtr((hwnd), GWLP_WNDPROC, (LPARAM)(WNDPROC)(lpfn)))

当您使用该类型的子类时,必须使用CallWindowProc()在需要时调用上一个窗口过程,不要直接调用该过程:< / p>

LRESULT CALLBACK __myNewWndProc__(HWND hEdit, UINT msg, WPARAM wParam, LPARAM lParam)
{
    //...
    // handle SHAutoComplete-specific messages
    return CallWindowProc(autoCompleteWndProc,hEdit,msg,wParam,lParam);
}

原因在文件中说明:

SetWindowLongPtr function

  

使用GWLP_WNDPROC索引调用SetWindowLongPtr会创建用于创建窗口的窗口类的子类。应用程序可以子类化系统类,但不应该为另一个进程创建的窗口类创建子类。 SetWindowLongPtr函数通过更改与特定窗口类关联的窗口过程来创建窗口子类,从而使系统调用新窗口过程而不是前一过程。 应用程序必须通过调用CallWindowProc将未通过新窗口过程处理的任何消息传递给上一个窗口过程。这允许应用程序创建一系列窗口过程。

CallWindowProc function

  

lpPrevWndFunc [in]
  类型:WNDPROC

     

上一个窗口过程。如果通过调用GetWindowLong函数并将nIndex参数设置为GWL_WNDPROC或DWL_DLGPROC来获取此值,则它实际上是窗口或对话框过程的地址,或仅对CallWindowProc有意义的特殊内部值。

你可能遇到后一种情况,试图调用不能直接调用的东西会崩溃。

话虽如此,你不应该使用SetWindowLongPtr()来进行子类化。请改用SetWindowSubClass()。阅读以下文章了解更多详情:

Subclassing Controls

Safer subclassing