Module: wine Branch: master Commit: 4dc304489f357c07a7cf269170cb61b888d7b49f URL: http://source.winehq.org/git/wine.git/?a=commit;h=4dc304489f357c07a7cf269170...
Author: Andrew Nguyen anguyen@codeweavers.com Date: Tue Feb 1 04:16:20 2011 -0600
shell32: Improve initialization state and parameter handling in IAutoComplete::Init.
---
dlls/shell32/autocomplete.c | 32 ++++++++-- dlls/shell32/tests/autocomplete.c | 113 ++++++++++++++++++++++++++++++++++-- 2 files changed, 131 insertions(+), 14 deletions(-)
diff --git a/dlls/shell32/autocomplete.c b/dlls/shell32/autocomplete.c index d1139e2..95db44c 100644 --- a/dlls/shell32/autocomplete.c +++ b/dlls/shell32/autocomplete.c @@ -67,7 +67,8 @@ typedef struct const IAutoComplete2Vtbl *lpVtbl; const IAutoCompleteDropDownVtbl *lpDropDownVtbl; LONG ref; - BOOL enabled; + BOOL initialized; + BOOL enabled; HWND hwndEdit; HWND hwndListBox; WNDPROC wpOrigEditProc; @@ -246,21 +247,31 @@ static HRESULT WINAPI IAutoComplete2_fnInit( { IAutoCompleteImpl *This = (IAutoCompleteImpl *)iface;
- TRACE("(%p)->(0x%08lx, %p, %s, %s)\n", - This, (long)hwndEdit, punkACL, debugstr_w(pwzsRegKeyPath), debugstr_w(pwszQuickComplete)); + TRACE("(%p)->(%p, %p, %s, %s)\n", + This, hwndEdit, punkACL, debugstr_w(pwzsRegKeyPath), debugstr_w(pwszQuickComplete));
if (This->options & ACO_SEARCH) FIXME(" ACO_SEARCH not supported\n"); if (This->options & ACO_FILTERPREFIXES) FIXME(" ACO_FILTERPREFIXES not supported\n"); if (This->options & ACO_USETAB) FIXME(" ACO_USETAB not supported\n"); if (This->options & ACO_RTLREADING) FIXME(" ACO_RTLREADING not supported\n");
- This->hwndEdit = hwndEdit; + if (!hwndEdit || !punkACL) + return E_INVALIDARG; + + if (This->initialized) + { + WARN("Autocompletion object is already initialized\n"); + /* This->hwndEdit is set to NULL when the edit window is destroyed. */ + return This->hwndEdit ? E_FAIL : E_UNEXPECTED; + }
if (FAILED (IUnknown_QueryInterface (punkACL, &IID_IEnumString, (LPVOID*)&This->enumstr))) { - TRACE("No IEnumString interface\n"); - return E_NOINTERFACE; + WARN("No IEnumString interface\n"); + return E_NOINTERFACE; }
+ This->initialized = TRUE; + This->hwndEdit = hwndEdit; This->wpOrigEditProc = (WNDPROC) SetWindowLongPtrW( hwndEdit, GWLP_WNDPROC, (LONG_PTR) ACEditSubclassProc); SetWindowLongPtrW( hwndEdit, GWLP_USERDATA, (LONG_PTR)This);
@@ -613,7 +624,14 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, } } - break; + break; + case WM_DESTROY: + { + WNDPROC proc = This->wpOrigEditProc; + + This->hwndEdit = NULL; + return CallWindowProcW(proc, hwnd, uMsg, wParam, lParam); + } default: return CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam); diff --git a/dlls/shell32/tests/autocomplete.c b/dlls/shell32/tests/autocomplete.c index 01b97c1..a96aa97 100644 --- a/dlls/shell32/tests/autocomplete.c +++ b/dlls/shell32/tests/autocomplete.c @@ -33,10 +33,113 @@ static HWND hMainWnd, hEdit; static HINSTANCE hinst; static int killfocus_count;
+static void test_invalid_init(void) +{ + HRESULT hr; + IAutoComplete *ac; + IUnknown *acSource; + HWND edit_control; + + /* AutoComplete instance */ + hr = CoCreateInstance(&CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER, + &IID_IAutoComplete, (void **)&ac); + if (hr == REGDB_E_CLASSNOTREG) + { + win_skip("CLSID_AutoComplete is not registered\n"); + return; + } + ok(hr == S_OK, "no IID_IAutoComplete (0x%08x)\n", hr); + + /* AutoComplete source */ + hr = CoCreateInstance(&CLSID_ACLMulti, NULL, CLSCTX_INPROC_SERVER, + &IID_IACList, (void **)&acSource); + if (hr == REGDB_E_CLASSNOTREG) + { + win_skip("CLSID_ACLMulti is not registered\n"); + IAutoComplete_Release(ac); + return; + } + ok(hr == S_OK, "no IID_IACList (0x%08x)\n", hr); + + edit_control = CreateWindowExA(0, "EDIT", "Some text", 0, 10, 10, 300, 300, + hMainWnd, NULL, hinst, NULL); + ok(edit_control != NULL, "Can't create edit control\n"); + + /* The refcount of acSource would be incremented on older Windows. */ + hr = IAutoComplete_Init(ac, NULL, acSource, NULL, NULL); + ok(hr == E_INVALIDARG || + broken(hr == S_OK), /* Win2k/XP/Win2k3 */ + "Init returned 0x%08x\n", hr); + if (hr == E_INVALIDARG) + { + LONG ref; + + IUnknown_AddRef(acSource); + ref = IUnknown_Release(acSource); + ok(ref == 1, "Expected AutoComplete source refcount to be 1, got %d\n", ref); + } + +if (0) +{ + /* Older Windows versions never check the window handle, while newer + * versions only check for NULL. Subsequent attempts to initialize the + * object after this call succeeds would fail, because initialization + * state is determined by whether a non-NULL window handle is stored. */ + hr = IAutoComplete_Init(ac, (HWND)0xdeadbeef, acSource, NULL, NULL); + ok(hr == S_OK, "Init returned 0x%08x\n", hr); + + /* Tests crash on older Windows. */ + hr = IAutoComplete_Init(ac, NULL, NULL, NULL, NULL); + ok(hr == E_INVALIDARG, "Init returned 0x%08x\n", hr); + + hr = IAutoComplete_Init(ac, edit_control, NULL, NULL, NULL); + ok(hr == E_INVALIDARG, "Init returned 0x%08x\n", hr); +} + + /* bind to edit control */ + hr = IAutoComplete_Init(ac, edit_control, acSource, NULL, NULL); + ok(hr == S_OK, "Init returned 0x%08x\n", hr); + + /* try invalid parameters after successful initialization .*/ + hr = IAutoComplete_Init(ac, NULL, NULL, NULL, NULL); + ok(hr == E_INVALIDARG || + hr == E_FAIL, /* Win2k/XP/Win2k3 */ + "Init returned 0x%08x\n", hr); + + hr = IAutoComplete_Init(ac, NULL, acSource, NULL, NULL); + ok(hr == E_INVALIDARG || + hr == E_FAIL, /* Win2k/XP/Win2k3 */ + "Init returned 0x%08x\n", hr); + + hr = IAutoComplete_Init(ac, edit_control, NULL, NULL, NULL); + ok(hr == E_INVALIDARG || + hr == E_FAIL, /* Win2k/XP/Win2k3 */ + "Init returned 0x%08x\n", hr); + + /* try initializing twice on the same control */ + hr = IAutoComplete_Init(ac, edit_control, acSource, NULL, NULL); + ok(hr == E_FAIL, "Init returned 0x%08x\n", hr); + + /* try initializing with a different control */ + hr = IAutoComplete_Init(ac, hEdit, acSource, NULL, NULL); + ok(hr == E_FAIL, "Init returned 0x%08x\n", hr); + + DestroyWindow(edit_control); + + /* try initializing with a different control after + * destroying the original initialization control */ + hr = IAutoComplete_Init(ac, hEdit, acSource, NULL, NULL); + ok(hr == E_UNEXPECTED || + hr == E_FAIL, /* Win2k/XP/Win2k3 */ + "Init returned 0x%08x\n", hr); + + IUnknown_Release(acSource); + IAutoComplete_Release(ac); +} static IAutoComplete *test_init(void) { HRESULT r; - IAutoComplete* ac; + IAutoComplete *ac; IUnknown *acSource;
/* AutoComplete instance */ @@ -60,14 +163,9 @@ static IAutoComplete *test_init(void) } ok(r == S_OK, "no IID_IACList (0x%08x)\n", r);
-if (0) -{ - /* crashes on native */ - r = IAutoComplete_Init(ac, hEdit, NULL, NULL, NULL); -} /* bind to edit control */ r = IAutoComplete_Init(ac, hEdit, acSource, NULL, NULL); - ok(r == S_OK, "Init failed (0x%08x)\n", r); + ok(r == S_OK, "Init returned 0x%08x\n", r);
IUnknown_Release(acSource);
@@ -135,6 +233,7 @@ START_TEST(autocomplete) ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n"); if (!hMainWnd) return;
+ test_invalid_init(); ac = test_init(); if (!ac) goto cleanup;