您的位置:首页 > 其它

SHAutoComplete

2013-12-12 23:38 141 查看
指示系统编辑控件使用自动完成,以帮助完成的URL或文件系统路径。

 

HRESULT SHAutoComplete(
_In_  HWND hwndEdit,
DWORD dwFlags
);

Parameters

hwndEdit [in] Type: HWND
The window handle of a system edit control. Typically, this parameter is the handle of an edit control or the edit control embedded in a ComboBoxEx control.
dwFlags Type: DWORD
The flags to control the operation of SHAutoComplete. The first four flags are used to override the Internet Explorer registry settings. The user can change these settings manually by launching the Internet Options property sheet from the Tools menu and clicking the Advanced tab.
SHACF_AUTOAPPEND_FORCE_OFF (0x80000000)
Ignore the registry default and force the AutoAppend feature off. This flag must be used in combination with one or more of the SHACF_FILESYS* or SHACF_URL* flags.
SHACF_AUTOAPPEND_FORCE_ON (0x40000000)
Ignore the registry value and force the AutoAppend feature on. The completed string will be displayed in the edit box with the added characters highlighted. This flag must be used in combination with one or more of the SHACF_FILESYS* or SHACF_URL* flags.
SHACF_AUTOSUGGEST_FORCE_OFF (0x20000000)
Ignore the registry default and force the AutoSuggest feature off. This flag must be used in combination with one or more of the SHACF_FILESYS* or SHACF_URL* flags.
SHACF_AUTOSUGGEST_FORCE_ON (0x10000000)
Ignore the registry value and force the AutoSuggest feature on. A selection of possible completed strings will be displayed as a drop-down list, below the edit box. This flag must be used in combination with one or more of the SHACF_FILESYS* or SHACF_URL* flags.
SHACF_DEFAULT (0x00000000)
The default setting, equivalent to SHACF_FILESYSTEM | SHACF_URLALL. SHACF_DEFAULT cannot be combined with any other flags.
SHACF_FILESYS_ONLY (0x00000010)
Include the file system only.
SHACF_FILESYS_DIRS (0x00000020)
Include the file system and directories, UNC servers, and UNC server shares.
SHACF_FILESYSTEM (0x00000001)
Include the file system and the rest of the Shell (Desktop, Computer, and Control Panel, for example).
SHACF_URLALL (SHACF_URLHISTORY | SHACF_URLMRU)
Include the URLs in the users History and Recently Used lists. Equivalent to SHACF_URLHISTORY | SHACF_URLMRU.
SHACF_URLHISTORY (0x00000002)
Include the URLs in the user's History list.
SHACF_URLMRU (0x00000004)
Include the URLs in the user's Recently Used list.
SHACF_USETAB (0x00000008)
Allow the user to select from the autosuggest list by pressing the TAB key. If this flag is not set, pressing the TAB key will shift focus to the next control and close the autosuggest list. If SHACF_USETAB is set, pressing the TAB key will select the first item in the list. Pressing TAB again will select the next item in the list, and so on. When the user reaches the end of the list, the next TAB key press will cycle the focus back to the edit control. This flag must be used in combination with one or more of the SHACF_FILESYS* or SHACF_URL* flags listed on this page.
SHACF_VIRTUAL_NAMESPACE (0x00000040)

Return value

Type: HRESULT
If this function succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.

 

Header
Shlwapi.h
Library
Shlwapi.lib
DLL
Shlwapi.dll (version 5.0 or later)
 1、SHAutoComplete简介
  Shlwapi.dll是微软提供的一个轻量级外壳工具函数库(Shell Lightweight Utility Functions),它提供了一些比较常用的函数,用以处理调色板、路径(如《Secrets in ShlWapi.Dll》中提到的PathCompactPath函数)、注册表、字符串等。从5.0版本(随Internet Explorer 5推出)开始,shlwapi.dll还提供了一个函数SHAutoComplete,它使得编辑框控件(如Edit、ComboBox)具有被称为“自动完成”的功能,即当用户在编辑框中输入的时候自动弹出一个非激活的窗口,为用户输入提供建议。如我们在Internet Explorer的地址栏输入“google”,如果系统记录了以前输入过“www.google.com”,则地址栏下方会显示出建议的网址。
  



  这样贴心的功能自然为IE 5赢得市场提供了帮助,而对开发人员来说,如果能够毫不费力地为自己的程序添加这样的功能则是再好不过。SHAutoComplete就是最直接而简单的选择。下面的代码演示了如何调用SHAutoComplete函数为某个Edit控件添加自动完成的功能:
  
  typedef HRESULT (CALLBACK* LPFNDLLFUNC)(HWND ,DWORD);
  HINSTANCE hIns = LoadLibrary(_T("shlwapi.dll"));
  if( hIns != NULL )
  {
  LPFNDLLFUNC lpfnDllFunc = (LPFNDLLFUNC)GetProcAddress(hIns, "SHAutoComplete");
  if( lpfnDllFunc != NULL )
  {
  lpfnDllFunc(m_wndAddressBar.m_hWnd, SHACF_AUTOAPPEND_FORCE_ON |
  SHACF_AUTOSUGGEST_FORCE_ON | SHACF_URLALL);
  }
  FreeLibrary(hIns);
  }
  
  从微软的习惯来说,这种对用户来说极为有用的功能不会只提供这样一个简单的函数就完事。事实上,SHAutoComplete只完成系统默认实现的功能,开发人员如果需要自定义以提供更强功能的话则可通过实现IAutoComplete接口以及IAutoComplete2接口来完成(在Windows XP中还提供了IAutoCompleteDropDown接口用以控制上图中那个下拉列表窗口的状态)。
  2、问题的提出
  我们知道,当用户在ComboBox控件的下拉框中用鼠标点击某个列表项或在列表项上按回车键时,ComboBox的父窗口会通过WM_COMMAND消息接收到一个CBN_SELENDOK通知,从而可以知道用户选择了那一个列表项并进行处理,在VC++中类似这样:
  
  BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
  ON_CBN_SELENDOK(ID_ADDRESSBOX, &CMainFrame::OnSelAddress)
  ......
  END_MESSAGE_MAP()
  void CMainFrame::OnSelAddress()
  {
  CString str = m_wndAddressBar.GetLBAddress();
  ...... //处理用户的选择
  }
  
  自然而然地,对于SHAutoComplete提供的下拉框,我们也希望有这样的通知,但MSDN中似乎并没有相关的文档。
  3、SPY++
  我们马上想到用Spy++来跟踪消息。以IE的地址栏为例,当我们在SHAutoComplete的下拉框中点击(按回车键有同样的效果)“http://www.google.com” 这个列表项时,地址栏中的Edit的消息踪迹如下所示:
  
  <00589> 001B0BF4 S WM_SETTEXT lpsz:0013D074 ("http://www.google.com")
  ......
  <00606> 001B0BF4 R EM_SETSEL
  <00607> 001B0BF4 S message:0xC2B6 [Registered:"AC_ItemActivate"] wParam:00000000 lParam:0013D494
  <00608> 001B0BF4 R message:0xC2B6 [Registered:"AC_ItemActivate"] lResult:00000000
  <00609> 001B0BF4 S WM_KEYDOWN nVirtKey:VK_RETURN cRepeat:0 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
  ......
  
  包含Registered:"AC_ItemActivate"的这一行立刻引起了我们的注意。这是一个用RegisterWindowMessage函数在运行时向系统注册的消息(参见《Windows通知栏图标高级编程概述》和《具有自动恢复功能的通知栏图标控件》),从其字面意思来看正是我们想要的。我们注意到Edit在接收到该消息之前还接收到了WM_SETTEXT消息,即此刻Edit中的文字已经被SHAutoComplete的后台工作设置为我们所选择的列表项了,因此对于该消息的wParam和lParam的意义我们也可以不去深究。
  4、问题解决
  下面是一个简单的解决方案:
  
  // CACEditSubclassWnd
  class CACEditSubclassWnd : public CWnd
  {
  DECLARE_DYNAMIC(CACEditSubclassWnd)
  static const UINT m_nAcItemActivateMsg;
  //用来保存向系统注册的消息
  public:
  CACEditSubclassWnd(){};
  virtual ~CACEditSubclassWnd(){};
  protected:
  LRESULT OnAcItemActivate(WPARAM wParam, LPARAM lParam);
  DECLARE_MESSAGE_MAP()
  };
  // CACEditSubclassWnd
  // 向系统注册我们需要的消息
  const UINT CACEditSubclassWnd::m_nAcItemActivateMsg = ::RegisterWindowMessage(_T("AC_ItemActivate"));
  IMPLEMENT_DYNAMIC(CACEditSubclassWnd, CWnd)
  BEGIN_MESSAGE_MAP(CACEditSubclassWnd, CWnd)
  ON_REGISTERED_MESSAGE(CACEditSubclassWnd::m_nAcItemActivateMsg, &CACEditSubclassWnd::OnAcItemActivate)
  END_MESSAGE_MAP()
  // CACEditSubclassWnd message handlers
  LRESULT CACEditSubclassWnd::OnAcItemActivate(WPARAM wParam, LPARAM lParam)
  {
  AfxGetMainWnd()->SendMessage(WM_COMMAND, MAKEWPARAM(LOWORD(ACCBN_SELENDOK), 0x0), 0);
  //ACCBN_SELENDOK是我们自定义的通知
  return 0L;
  }
  
  假设CUrlAddressCombo是一个地址栏类,则为其声明一个CACEditSubclassWnd类型的成员,并在适当的位置(如Init成员函数中)子类化Edit控件。
  
  class CUrlAddressCombo : public CComboBoxEx
  {
  private:
  CACEditSubclassWnd m_ACEditSubclassWnd;
  ......
  }
  void CUrlAddressCombo::Init(void)
  {
  m_ACEditSubclassWnd.SubclassWindow( GetEditCtrl()->m_hWnd );
  }
  而在CMainFrame中可以这样实现:
  
  BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
  ON_COMMAND(ACCBN_SELENDOK, &CMainFrame::OnACSelEndOk)
  ......
  END_MESSAGE_MAP()
  void CMainFrame::OnACSelEndOk()
  {
  CString strAddr;
  m_wndAddressBar.GetEditCtrl()->GetWindowText(strAddr);
  ...... //处理用户的选择
  }
  
  非常简单,不是吗?
  5、参考文献
  MSDN: SHAutoComplete Function
  引用地址:《响应AutoComplete下拉列表的选择事件》(王朝网络 wangchao.net.cn)
 

要最简单地实现AutoComplete,只要下面那样调用ShAutoComplete函数即可:
SHAutoComplete(GetDlgItem (hDlg,IDC_EDIT2),SHACF_FILESYSTEM|SHACF_AUTOSUGGEST_FORCE_ON);
SHAutoComplete的第一个参数,是edit控件的句柄(或者是ComboBox中edit控件的句柄)。第二个参 数是一些flag,来控制提示的内容来自于文件系统(SHACF_FILESYSTEM等)还是历史url地址 (SHACF_URLHISTORY,SHACF_URLMRU等),或者全部。同时,还可以控制是否强制启用或关闭AutoAppend 和AutoSuggest功能。这两种功能的默认设置在ie的设置程序中或在注册表中:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\AutoComplete
AutoAppend 指的是根据你当前输入的内容,自动插入剩余的部分。例如:在AutoComplete的系统中 存在apple这个词条,那么当你键入app的时候,则系统会自动插入剩下的le,并将le以选中的方式显示 。类似于:app|le  
AutoSuggest 启用的话,会自动出现下列表框显示候选的内容。
最后,不要忘记在程序开头调用CoInitialize,因为这东西和com有关。
自定义AutoComplete
SHAutoComplete的功能是十分的局限的,只能提供文件系统或url地址的自动完成。在大部分情况下 ,我们需要对自动完成的内容自定义。这时,我们需要的是shell提供的AutoComplete对象,并实现 IEnumString接口。简单的代码如下:
IAutoComplete * pac;
CoCreateInstance(CLSID_AutoComplete,NULL,CLSCTX_INPROC_SERVER,IID_IAutoComplete,(void**) &pac);
pac->Init(GetDlgItem(IDC_EDIT3),<你实现的IEnumString指针>,0,0);

然后,设置一些参数,比如:是否启用AutoAppend,AutoSuggest等:
IAutoComplete * pac2;
pac->QueryInterface(IID_IAutoComplete2,(void**)&pac2);
pac2->SetOptions(ACO_AUTOSUGGEST|ACO_AUTOAPPEND|ACO_UPDOWNKEYDROPSLIST);

最后,说明一下IEnumString的实现。IEnumString类似于大部分的IEnumXXXX本身非常简单,唯一需 要提一下的就是IEnumString::Next返回字符串需要调用CoTaskMemAlloc分配内存。代码如下:
STDMETHOD(Next( ULONG celt,LPOLESTR * rgelt,ULONG * pceltFetched))
{
  ULONG i=0;
  if (pceltFetched)*pceltFetched=0;
  for (;m_idx<(int)m_vec.GetCount() && i<CELT;++I,++M_IDX)
  {
    //注意CoTaskMemAlloc接受的参数是字节数,GetLength是返回的字符数。并要加上结尾'\0'的 字节
    rgelt[i] =(LPOLESTR)CoTaskMemAlloc(2 + m_vec[m_idx].GetLength() * 2);
    wcscpy(rgelt[i],m_vec[m_idx]);
    if (pceltFetched) ++(*pceltFetched);
  }
  return i==celt?S_OK:S_FALSE;
}

这样,遍完成了自定义的AutoComplete。很简单,不是吗?
更进一步
如果候选的内容比较多,为了提高性能,可以再实现IACList接口。IACList只有一个方法:
HRESULT Expand(LPCWSTR pszExpand);
每次Expand被调用的时候,便生成一个pszExpand开头的候选列表。之后IEnumString接口的方法被调 用的时候,就从这个列表中取字符串。
例如:做一个文件系统的自动完成。用户输入"C:\",然后Expand(L"C:\\")被 调用,则枚举C:\下面所有文件保存起来,然后IEnumString的方法则返回这些文件的路径。
另外,windows还提供的Compound AutoComplete等等这些组件。关于这些,请看Using Autocomplete 。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: