[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