diff --git a/dlls/shell32/tests/shelldispatch.c b/dlls/shell32/tests/shelldispatch.c index c1e3fbcdaf1..eea505ff61d 100644 --- a/dlls/shell32/tests/shelldispatch.c +++ b/dlls/shell32/tests/shelldispatch.c @@ -1035,15 +1035,12 @@ static void test_ShellWindows(void) ok(hr == HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), "got 0x%08x\n", hr); hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, &cookie); -todo_wine ok(hr == E_POINTER, "got 0x%08x\n", hr); hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie); -todo_wine ok(hr == E_POINTER, "got 0x%08x\n", hr); hr = IShellWindows_Register(shellwindows, (IDispatch*)shellwindows, 0, SWC_EXPLORER, &cookie); -todo_wine ok(hr == E_POINTER, "got 0x%08x\n", hr); hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP, @@ -1052,16 +1049,13 @@ todo_wine cookie = 0; hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie); -todo_wine { ok(hr == S_OK, "got 0x%08x\n", hr); ok(cookie != 0, "got %d\n", cookie); -} + cookie2 = 0; hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_EXPLORER, &cookie2); -todo_wine { ok(hr == S_OK, "got 0x%08x\n", hr); ok(cookie2 != 0 && cookie2 != cookie, "got %d\n", cookie2); -} pidl = ILCreateFromPathA("C:\\"); V_VT(&v) = VT_ARRAY | VT_UI1; @@ -1083,7 +1077,6 @@ todo_wine { ok(!disp, "Got IDispatch %p.\n", &disp); hr = IShellWindows_Revoke(shellwindows, cookie); -todo_wine ok(hr == S_OK, "got 0x%08x\n", hr); hr = IShellWindows_FindWindowSW(shellwindows, &v, &v2, SWC_EXPLORER, &ret, 0, &disp); @@ -1092,20 +1085,17 @@ todo_wine ok(!disp, "Got IDispatch %p.\n", &disp); hr = IShellWindows_Revoke(shellwindows, cookie2); -todo_wine ok(hr == S_OK, "got 0x%08x\n", hr); hr = IShellWindows_Revoke(shellwindows, 0); -todo_wine ok(hr == S_FALSE, "got 0x%08x\n", hr); /* we can register ourselves as desktop, but FindWindowSW still returns real desktop window */ cookie = 0; hr = IShellWindows_Register(shellwindows, NULL, HandleToLong(hwnd), SWC_DESKTOP, &cookie); -todo_wine { ok(hr == S_OK, "got 0x%08x\n", hr); ok(cookie != 0, "got %d\n", cookie); -} + disp = (void*)0xdeadbeef; ret = 0xdead; VariantInit(&v); @@ -1235,7 +1225,6 @@ todo_wine ok(ret == 0, "got %d\n", ret); hr = IShellWindows_Revoke(shellwindows, cookie); -todo_wine ok(hr == S_OK, "got 0x%08x\n", hr); DestroyWindow(hwnd); IShellWindows_Release(shellwindows); diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c index bac17dcc5fb..53dcd218178 100644 --- a/programs/explorer/desktop.c +++ b/programs/explorer/desktop.c @@ -118,9 +118,48 @@ static HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo) return S_OK; } +static BOOL array_reserve(void **elements, unsigned int *capacity, unsigned int count, unsigned int size) +{ + unsigned int new_capacity, max_capacity; + void *new_elements; + + if (count <= *capacity) + return TRUE; + + max_capacity = ~(SIZE_T)0 / size; + if (count > max_capacity) + return FALSE; + + new_capacity = max(4, *capacity); + while (new_capacity < count && new_capacity <= max_capacity / 2) + new_capacity *= 2; + if (new_capacity < count) + new_capacity = max_capacity; + + if (!(new_elements = realloc(*elements, new_capacity * size))) + return FALSE; + + *elements = new_elements; + *capacity = new_capacity; + + return TRUE; +} + +static LONG cookie_counter; + +struct window +{ + LONG cookie, hwnd; + int class; +}; + struct shellwindows { IShellWindows IShellWindows_iface; + CRITICAL_SECTION cs; + + unsigned int count, max; + struct window *windows; }; /* This is not limited to desktop itself, every file browser window that @@ -1140,10 +1179,34 @@ static HRESULT WINAPI shellwindows__NewEnum(IShellWindows *iface, IUnknown **ppu } static HRESULT WINAPI shellwindows_Register(IShellWindows *iface, - IDispatch *disp, LONG hWnd, int class, LONG *cookie) + IDispatch *disp, LONG hwnd, int class, LONG *cookie) { - FIXME("%p 0x%x 0x%x %p\n", disp, hWnd, class, cookie); - return E_NOTIMPL; + struct shellwindows *sw = impl_from_IShellWindows(iface); + struct window *window; + + TRACE("iface %p, disp %p, hwnd %#x, class %u, cookie %p.\n", iface, disp, hwnd, class, cookie); + + if (!hwnd) + return E_POINTER; + + if (disp) + FIXME("Ignoring IDispatch %p.\n", disp); + + EnterCriticalSection(&sw->cs); + + if (!array_reserve((void **)&sw->windows, &sw->max, sw->count + 1, sizeof(*sw->windows))) + { + LeaveCriticalSection(&sw->cs); + return E_OUTOFMEMORY; + } + + window = &sw->windows[sw->count++]; + window->hwnd = hwnd; + window->class = class; + *cookie = window->cookie = ++cookie_counter; + + LeaveCriticalSection(&sw->cs); + return S_OK; } static HRESULT WINAPI shellwindows_RegisterPending(IShellWindows *iface, @@ -1156,8 +1219,26 @@ static HRESULT WINAPI shellwindows_RegisterPending(IShellWindows *iface, static HRESULT WINAPI shellwindows_Revoke(IShellWindows *iface, LONG cookie) { - FIXME("0x%x\n", cookie); - return E_NOTIMPL; + struct shellwindows *sw = impl_from_IShellWindows(iface); + unsigned int i; + + TRACE("iface %p, cookie %u.\n", iface, cookie); + + EnterCriticalSection(&sw->cs); + + for (i = 0; i < sw->count; ++i) + { + if (sw->windows[i].cookie == cookie) + { + --sw->count; + memmove(&sw->windows[i], &sw->windows[i + 1], (sw->count - i) * sizeof(*sw->windows)); + LeaveCriticalSection(&sw->cs); + return S_OK; + } + } + + LeaveCriticalSection(&sw->cs); + return S_FALSE; } static HRESULT WINAPI shellwindows_OnNavigate(IShellWindows *iface, LONG cookie, VARIANT *loc) @@ -2157,6 +2238,8 @@ static void shellwindows_init(void) CoInitialize(NULL); shellwindows.IShellWindows_iface.lpVtbl = &shellwindowsvtbl; + InitializeCriticalSection(&shellwindows.cs); + shellwindows.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": shellwindows.cs"); hr = CoRegisterClassObject(&CLSID_ShellWindows, (IUnknown*)&shellwindows_classfactory.IClassFactory_iface,