[PATCH] shlwapi: initial implement of SHAutoComplete

Hirofumi Katayama katayama.hirofumi.mz at gmail.com
Sat May 22 20:09:20 CDT 2010


See attachment.
-------------- next part --------------
From 2730d61a4edef8890e47455628325e0710174e90 Mon Sep 17 00:00:00 2001
From: Katayama Hirofumi MZ <katayama.hirofumi.mz at gmail.com>
Date: Sat, 22 May 2010 16:58:20 +0900
Subject: [PATCH] shlwapi: initial implement of SHAutoComplete

---
 dlls/shlwapi/url.c |  392 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 390 insertions(+), 2 deletions(-)

diff --git a/dlls/shlwapi/url.c b/dlls/shlwapi/url.c
index fb9b932..c7b5d1f 100644
--- a/dlls/shlwapi/url.c
+++ b/dlls/shlwapi/url.c
@@ -32,6 +32,8 @@
 #include "winreg.h"
 #include "winternl.h"
 #define NO_SHLWAPI_STREAM
+#include "shlobj.h"
+#include "shldisp.h"
 #include "shlwapi.h"
 #include "intshcut.h"
 #include "wine/debug.h"
@@ -2361,6 +2363,308 @@ HRESULT WINAPI UrlCreateFromPathW(LPCWSTR pszPath, LPWSTR pszUrl, LPDWORD pcchUr
     return ret;
 }
 
+/****************************************************************************/
+
+static const WCHAR szMRUList[] = L"MRUList";
+static const WCHAR szRunMRU[] =
+    L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU";
+
+void *my_malloc(UINT size)
+{
+    return HeapAlloc(GetProcessHeap(), 0, size);
+}
+
+void *my_realloc(void *p, UINT size)
+{
+    if (p == NULL)
+        return my_malloc(size);
+    return HeapReAlloc(GetProcessHeap(), 0, p, size);
+}
+
+void my_free(void *p)
+{
+    HeapFree(GetProcessHeap(), 0, p);
+}
+
+LPWSTR my__wcsdup(LPCWSTR p)
+{
+    LPWSTR pNew;
+    pNew = my_malloc((strlenW(p) + 1) * sizeof(WCHAR));
+    if (pNew != NULL)
+        strcpyW(pNew, p);
+    return pNew;
+}
+
+#define malloc my_malloc
+#define realloc my_realloc
+#define free my_free
+#define _wcsdup my__wcsdup
+
+/****************************************************************************
+ * IEnumString
+ */
+
+STDMETHODIMP IEnumString_fnQueryInterface(IEnumString *pEnumString, REFIID riid, void** ppvObject);
+STDMETHODIMP_(ULONG) IEnumString_fnAddRef(IEnumString *pEnumString);
+STDMETHODIMP_(ULONG) IEnumString_fnRelease(IEnumString *pEnumString);
+STDMETHODIMP IEnumString_fnNext(IEnumString *pEnumString, ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched);
+STDMETHODIMP IEnumString_fnSkip(IEnumString *pEnumString, ULONG celt);
+STDMETHODIMP IEnumString_fnReset(IEnumString *pEnumString);
+STDMETHODIMP IEnumString_fnClone(IEnumString *pEnumString, IEnumString **ppenum);
+
+static IEnumStringVtbl EnumStringVtbl =
+{
+    IEnumString_fnQueryInterface,
+    IEnumString_fnAddRef,
+    IEnumString_fnRelease,
+    IEnumString_fnNext,
+    IEnumString_fnSkip,
+    IEnumString_fnReset,
+    IEnumString_fnClone
+};
+
+typedef struct 
+{
+    IEnumStringVtbl *lpVtbl;
+    LONG        m_lRef;
+    IMalloc *   m_pMalloc;
+    INT         m_i;
+    INT         m_c;
+    LPWSTR *    m_strings;
+} EnumStringImpl;
+
+LPWSTR *GetMRUStrings(INT *Count)
+{
+    HKEY hKey;
+    DWORD len;
+    LPWSTR list, *strings;
+    WCHAR name[2], path[MAX_PATH];
+    INT i;
+
+    strings = NULL;
+    *Count = 0;
+    if (RegOpenKeyExW(HKEY_CURRENT_USER, szRunMRU, 0, KEY_READ, &hKey) !=
+        ERROR_SUCCESS)
+        return NULL;
+
+    if (RegQueryValueExW(hKey, szMRUList, NULL, NULL, NULL, &len) ==
+        ERROR_SUCCESS)
+    {
+        list = (LPWSTR) malloc(len);
+        if (RegQueryValueExW(hKey, szMRUList, NULL, NULL, (LPBYTE) list, 
+                             &len) == ERROR_SUCCESS)
+        {
+            for(i = 0; list[i]; i++)
+            {
+                name[0] = list[i];
+                name[1] = 0;
+                len = MAX_PATH * sizeof(WCHAR);
+                if (RegQueryValueExW(hKey, name, NULL, NULL, (LPBYTE) path, 
+                                     &len) == ERROR_SUCCESS)
+                {
+                    len = lstrlenW(path);
+                    if (len > 1 && path[len - 2] == '\\' && iswdigit(path[len - 1]))
+                        path[len - 2] = 0;
+                    (*Count)++;
+                    strings = (LPWSTR *) realloc(strings, *Count * sizeof(LPWSTR));
+                    strings[*Count - 1] = _wcsdup(path);
+                    if (strings[*Count - 1] == NULL)
+                        (*Count)--;
+                }
+            }
+        }
+    }
+    RegCloseKey(hKey);
+    return strings;
+}
+
+EnumStringImpl *IEnumString_construct(VOID)
+{
+    EnumStringImpl *pEnumString;
+
+    pEnumString = (EnumStringImpl *) malloc(sizeof(EnumStringImpl));
+    if (pEnumString != NULL)
+    {
+        pEnumString->lpVtbl = &EnumStringVtbl;
+        pEnumString->m_lRef = 0;
+        pEnumString->m_pMalloc = NULL;
+        SHGetMalloc(&pEnumString->m_pMalloc);
+        pEnumString->m_i = 0;
+        pEnumString->m_strings = GetMRUStrings(&pEnumString->m_c);
+    }
+    return pEnumString;
+}
+
+VOID IEnumString_destruct(EnumStringImpl *pEnumString)
+{
+    INT i;
+    if (pEnumString->m_pMalloc != NULL)
+        pEnumString->m_pMalloc->lpVtbl->Release(pEnumString->m_pMalloc);
+    if (pEnumString->m_strings != NULL)
+    {
+        for(i = 0; i < pEnumString->m_c; i++)
+            free(pEnumString->m_strings[i]);
+        free(pEnumString->m_strings);
+    }
+    free(pEnumString);
+}
+
+STDMETHODIMP IEnumString_fnQueryInterface(IEnumString *pEnumString, REFIID riid, void** ppvObject)
+{
+    *ppvObject = NULL;
+
+    if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumString, riid))
+    {
+        *ppvObject = (void *) pEnumString;
+        pEnumString->lpVtbl->AddRef(pEnumString);
+        return S_OK;
+    }
+    return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG) IEnumString_fnAddRef(IEnumString *pEnumString)
+{
+    EnumStringImpl *this = (EnumStringImpl *) pEnumString;
+    this->m_lRef++;
+    return (ULONG) this->m_lRef;
+}
+
+STDMETHODIMP_(ULONG) IEnumString_fnRelease(IEnumString *pEnumString)
+{
+    EnumStringImpl *this = (EnumStringImpl *) pEnumString;
+    if (--this->m_lRef == 0)
+    {
+        IEnumString_destruct(this);
+        return 0;
+    }
+    return (ULONG) this->m_lRef;
+}
+
+STDMETHODIMP IEnumString_fnNext(IEnumString *pEnumString, ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched)
+{
+    ULONG i, size;
+    EnumStringImpl *this = (EnumStringImpl *) pEnumString;
+
+    if (pceltFetched != NULL)
+        *pceltFetched = 0;
+
+    if (rgelt == NULL)
+    {
+        if (celt != 1)
+            return E_POINTER;
+    }
+
+    if (this->m_c <= this->m_i)
+        return S_FALSE;
+
+    for(i = 0; i < celt; i++, this->m_i++)
+    {
+        if (this->m_c <= this->m_i)
+            break;
+        size = lstrlenW(this->m_strings[this->m_i]) + 1;
+        rgelt[i] = (LPOLESTR) this->m_pMalloc->lpVtbl->Alloc(this->m_pMalloc, size * sizeof(WCHAR));
+        if (rgelt[i] != NULL)
+            wcscpy(rgelt[i], this->m_strings[this->m_i]);
+    }
+
+    if (pceltFetched != NULL)
+        *pceltFetched = i;
+
+    return S_OK;
+}
+
+STDMETHODIMP IEnumString_fnSkip(IEnumString *pEnumString, ULONG celt)
+{
+    EnumStringImpl *this = (EnumStringImpl *) pEnumString;
+
+    this->m_i += celt;
+    if (this->m_c <= this->m_i)
+    {
+        this->m_i = this->m_c - 1;
+        return S_FALSE;
+    }
+    return S_OK;
+}
+
+STDMETHODIMP IEnumString_fnReset(IEnumString *pEnumString)
+{
+    EnumStringImpl *this = (EnumStringImpl *) pEnumString;
+
+    this->m_i = 0;
+    return S_OK;
+}
+
+STDMETHODIMP IEnumString_fnClone(IEnumString *pEnumString, IEnumString **ppenum)
+{
+    INT i;
+    EnumStringImpl *pNew;
+    EnumStringImpl *this = (EnumStringImpl *) pEnumString;
+
+    *ppenum = NULL;
+    pNew = IEnumString_construct();
+
+    if (pNew == NULL)
+        return E_OUTOFMEMORY;
+
+    pNew->lpVtbl->AddRef((IEnumString *) pNew);
+    pNew->m_i = this->m_i;
+    pNew->m_c = this->m_c;
+    pNew->m_strings = (LPWSTR *) malloc(this->m_c * sizeof(LPWSTR));
+    for(i = 0; i < this->m_c; i++)
+    {
+        pNew->m_strings[i] = (LPWSTR) _wcsdup(this->m_strings[i]);
+    }
+    *ppenum = (IEnumString *) pNew;
+    return S_OK;
+}
+
+/****************************************************************************/
+
+typedef struct
+{
+    WNDPROC             fnOldWndProc;
+    EnumStringImpl *    pEnumString;
+    IAutoComplete *     pAutoComplete;
+} AUTOCOMPLETEPROP;
+
+static const WCHAR szPropName[] = L"SHAutoCompleteProp";
+
+LRESULT CALLBACK AutoCompleteEditWndProc(
+    HWND    hWnd,
+    UINT    uMsg,
+    WPARAM  wParam,
+    LPARAM  lParam)
+{
+    AUTOCOMPLETEPROP *pProp;
+    WNDPROC fnOldWndProc;
+
+    pProp = (AUTOCOMPLETEPROP *) GetPropW(hWnd, szPropName);
+    if (pProp != NULL)
+        fnOldWndProc = pProp->fnOldWndProc;
+    else
+        fnOldWndProc = NULL;
+
+    switch(uMsg)
+    {
+    case WM_DESTROY:
+        if (pProp != NULL)
+        {
+            SetPropW(hWnd, szPropName, NULL);
+            pProp->pAutoComplete->lpVtbl->Enable(pProp->pAutoComplete, FALSE);
+            pProp->pEnumString->lpVtbl->Release((IEnumString *) pProp->pEnumString);
+            pProp->pAutoComplete->lpVtbl->Release(pProp->pAutoComplete);
+            free(pProp);
+            SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR) fnOldWndProc);
+        }
+        /* FALL THRU */
+
+    default:
+        if (fnOldWndProc != NULL)
+            return CallWindowProc(fnOldWndProc, hWnd, uMsg, wParam, lParam);
+    }
+    return 0;
+}
+
 /*************************************************************************
  *      SHAutoComplete  	[SHLWAPI.@]
  *
@@ -2376,8 +2680,92 @@ HRESULT WINAPI UrlCreateFromPathW(LPCWSTR pszPath, LPWSTR pszUrl, LPDWORD pcchUr
  */
 HRESULT WINAPI SHAutoComplete(HWND hwndEdit, DWORD dwFlags)
 {
-  FIXME("stub\n");
-  return S_FALSE;
+    HRESULT hResult;
+    AUTOCOMPLETEPROP *pProp;
+    EnumStringImpl *pEnumString;
+    IAutoComplete *pAutoComplete;
+    IAutoComplete2 *pAutoComplete2;
+    DWORD Options;
+
+    pEnumString = IEnumString_construct();
+    if (pEnumString == NULL)
+        return E_OUTOFMEMORY;
+
+    pProp = (AUTOCOMPLETEPROP *) GetPropW(hwndEdit, szPropName);
+    if (pProp != NULL)
+    {
+        pProp->pAutoComplete->lpVtbl->Enable(pProp->pAutoComplete, FALSE);
+        pProp->pEnumString->lpVtbl->Release((IEnumString *) pProp->pEnumString);
+        pProp->pEnumString = pEnumString;
+        pAutoComplete = pProp->pAutoComplete;
+        pAutoComplete->lpVtbl->Init(pAutoComplete, hwndEdit, (IUnknown *) pEnumString, NULL, NULL);
+        hResult = pAutoComplete->lpVtbl->QueryInterface(pAutoComplete, &IID_IAutoComplete2,
+                      (void **) &pAutoComplete2);
+        if (SUCCEEDED(hResult))
+        {
+            /* FIXME: SHACF_* */
+            if ((dwFlags & SHACF_AUTOAPPEND_FORCE_OFF) &&
+                (dwFlags & SHACF_AUTOSUGGEST_FORCE_OFF))
+                Options = ACO_NONE;
+            else if (dwFlags & SHACF_AUTOAPPEND_FORCE_ON)
+                Options = ACO_AUTOAPPEND;
+            else
+                Options = ACO_AUTOSUGGEST;
+            if (dwFlags & SHACF_USETAB)
+                Options |= ACO_USETAB;
+            pAutoComplete2->lpVtbl->SetOptions(pAutoComplete2, Options);
+            pAutoComplete2->lpVtbl->Release(pAutoComplete2);
+        }
+        pAutoComplete->lpVtbl->Enable(pAutoComplete, TRUE);
+        return S_OK;
+    }
+
+    pProp = (AUTOCOMPLETEPROP *) malloc(sizeof(AUTOCOMPLETEPROP));
+    if (pProp == NULL)
+    {
+        pEnumString->lpVtbl->Release((IEnumString *) pEnumString);
+        return E_OUTOFMEMORY;
+    }
+    pProp->fnOldWndProc = (WNDPROC) SetWindowLongPtr(hwndEdit, GWLP_WNDPROC, (LONG_PTR) AutoCompleteEditWndProc);
+
+    hResult = CoCreateInstance(&CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER,
+            &IID_IAutoComplete, (void **) &pAutoComplete);
+    if (SUCCEEDED(hResult))
+    {
+        pAutoComplete->lpVtbl->AddRef(pAutoComplete);
+        hResult = pAutoComplete->lpVtbl->Init(pAutoComplete, hwndEdit, (IUnknown *) pEnumString, NULL, NULL);
+        if (SUCCEEDED(hResult))
+        {
+            hResult = pAutoComplete->lpVtbl->QueryInterface(pAutoComplete, &IID_IAutoComplete2,
+                          (void **)&pAutoComplete2);
+            if (SUCCEEDED(hResult))
+            {
+                /* FIXME: SHACF_* */
+                if ((dwFlags & SHACF_AUTOAPPEND_FORCE_OFF) &&
+                    (dwFlags & SHACF_AUTOSUGGEST_FORCE_OFF))
+                    Options = ACO_NONE;
+                else if (dwFlags & SHACF_AUTOAPPEND_FORCE_ON)
+                    Options = ACO_AUTOAPPEND;
+                else
+                    Options = ACO_AUTOSUGGEST;
+                if (dwFlags & SHACF_USETAB)
+                    Options |= ACO_USETAB;
+                pAutoComplete2->lpVtbl->SetOptions(pAutoComplete2, Options);
+                pAutoComplete2->lpVtbl->Release(pAutoComplete2);
+
+                pProp->pEnumString = pEnumString;
+                pProp->pAutoComplete = pAutoComplete;
+                SetPropW(hwndEdit, szPropName, pProp);
+                return S_OK;
+            }
+        }
+        pAutoComplete->lpVtbl->Release(pAutoComplete);
+    }
+
+    IEnumString_destruct(pEnumString);
+    free(pProp);
+
+    return hResult;
 }
 
 /*************************************************************************
-- 
1.6.1.3


More information about the wine-patches mailing list