Andrew Nguyen : shell32: Improve initialization state and parameter handling in IAutoComplete::Init .

Alexandre Julliard julliard at winehq.org
Tue Feb 1 12:24:57 CST 2011


Module: wine
Branch: master
Commit: 4dc304489f357c07a7cf269170cb61b888d7b49f
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=4dc304489f357c07a7cf269170cb61b888d7b49f

Author: Andrew Nguyen <anguyen at 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;




More information about the wine-cvs mailing list