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