Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/oleacc/tests/main.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/dlls/oleacc/tests/main.c b/dlls/oleacc/tests/main.c index 5522867b085..2d6a6c4cc2c 100644 --- a/dlls/oleacc/tests/main.c +++ b/dlls/oleacc/tests/main.c @@ -27,6 +27,7 @@ #include <ole2.h> #include <commctrl.h> #include <oleacc.h> +#include <servprov.h>
#define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE @@ -1409,6 +1410,32 @@ static LRESULT WINAPI test_query_class(HWND hwnd, UINT msg, WPARAM wparam, LPARA return 0; }
+#define check_acc_proxy_service( acc ) \ + check_acc_proxy_service_( (acc), __LINE__) +static void check_acc_proxy_service_(IAccessible *acc, int line) +{ + IServiceProvider *service = NULL; + IUnknown *unk = NULL; + HRESULT hr; + + hr = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void **)&service); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + if (SUCCEEDED(hr)) + { + hr = IServiceProvider_QueryService(service, &IIS_IsOleaccProxy, &IID_IUnknown, (void **)&unk); + ok(hr == S_OK, "got %#lx\n", hr); + ok(!!unk, "unk == NULL\n"); + ok(iface_cmp(unk, (IUnknown*)acc), "unk != acc\n"); + IUnknown_Release(unk); + + unk = NULL; + hr = IServiceProvider_QueryService(service, &IID_IUnknown, &IID_IUnknown, (void **)&unk); + ok(hr == E_INVALIDARG, "got %#lx\n", hr); + ok(!unk, "unk != NULL\n"); + IServiceProvider_Release(service); + } +} + static void test_CreateStdAccessibleObject_classes(void) { static const struct { @@ -1463,6 +1490,7 @@ static void test_CreateStdAccessibleObject_classes(void) ok(hr == S_OK, "CreateStdAccessibleObject failed %lx\n", hr); if (tests[i].client) CHECK_CALLED(winproc_GETOBJECT); + check_acc_proxy_service(acc); IAccessible_Release(acc);
if (tests[i].window) @@ -1471,6 +1499,7 @@ static void test_CreateStdAccessibleObject_classes(void) ok(hr == S_OK, "CreateStdAccessibleObject failed %lx\n", hr); if (tests[i].window) CHECK_CALLED(winproc_GETOBJECT); + check_acc_proxy_service(acc); IAccessible_Release(acc);
SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)win_proc);
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/oleacc/client.c | 47 ++++++++++++++++++++++++++++++++++++ dlls/oleacc/oleacc_private.h | 1 + dlls/oleacc/tests/main.c | 26 +++++++++----------- dlls/oleacc/window.c | 47 ++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 14 deletions(-)
diff --git a/dlls/oleacc/client.c b/dlls/oleacc/client.c index 20993109d28..42d4e1ed19a 100644 --- a/dlls/oleacc/client.c +++ b/dlls/oleacc/client.c @@ -32,6 +32,7 @@ typedef struct { IAccessible IAccessible_iface; IOleWindow IOleWindow_iface; IEnumVARIANT IEnumVARIANT_iface; + IServiceProvider IServiceProvider_iface;
LONG ref;
@@ -114,6 +115,8 @@ static HRESULT WINAPI Client_QueryInterface(IAccessible *iface, REFIID riid, voi *ppv = &This->IOleWindow_iface; }else if(IsEqualIID(riid, &IID_IEnumVARIANT)) { *ppv = &This->IEnumVARIANT_iface; + }else if(IsEqualIID(riid, &IID_IServiceProvider)) { + *ppv = &This->IServiceProvider_iface; }else { WARN("no interface: %s\n", debugstr_guid(riid)); *ppv = NULL; @@ -703,6 +706,49 @@ static const IEnumVARIANTVtbl ClientEnumVARIANTVtbl = { Client_EnumVARIANT_Clone };
+static inline Client* impl_from_Client_ServiceProvider(IServiceProvider *iface) +{ + return CONTAINING_RECORD(iface, Client, IServiceProvider_iface); +} + +static HRESULT WINAPI Client_ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + Client *This = impl_from_Client_ServiceProvider(iface); + return IAccessible_QueryInterface(&This->IAccessible_iface, riid, ppv); +} + +static ULONG WINAPI Client_ServiceProvider_AddRef(IServiceProvider *iface) +{ + Client *This = impl_from_Client_ServiceProvider(iface); + return IAccessible_AddRef(&This->IAccessible_iface); +} + +static ULONG WINAPI Client_ServiceProvider_Release(IServiceProvider *iface) +{ + Client *This = impl_from_Client_ServiceProvider(iface); + return IAccessible_Release(&This->IAccessible_iface); +} + +static HRESULT WINAPI Client_ServiceProvider_QueryService(IServiceProvider *iface, REFGUID guid_service, + REFIID riid, void **ppv) +{ + Client *This = impl_from_Client_ServiceProvider(iface); + + TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid_service), debugstr_guid(riid), ppv); + + if (IsEqualIID(guid_service, &IIS_IsOleaccProxy)) + return IAccessible_QueryInterface(&This->IAccessible_iface, riid, ppv); + + return E_INVALIDARG; +} + +static const IServiceProviderVtbl ClientServiceProviderVtbl = { + Client_ServiceProvider_QueryInterface, + Client_ServiceProvider_AddRef, + Client_ServiceProvider_Release, + Client_ServiceProvider_QueryService +}; + static void edit_init(Client *client) { client->role = ROLE_SYSTEM_TEXT; @@ -872,6 +918,7 @@ HRESULT create_client_object(HWND hwnd, const IID *iid, void **obj) client->IAccessible_iface.lpVtbl = &ClientVtbl; client->IOleWindow_iface.lpVtbl = &ClientOleWindowVtbl; client->IEnumVARIANT_iface.lpVtbl = &ClientEnumVARIANTVtbl; + client->IServiceProvider_iface.lpVtbl = &ClientServiceProviderVtbl; client->ref = 1; client->hwnd = hwnd; client->enum_pos = 0; diff --git a/dlls/oleacc/oleacc_private.h b/dlls/oleacc/oleacc_private.h index a01fc3615fe..c91b1465a79 100644 --- a/dlls/oleacc/oleacc_private.h +++ b/dlls/oleacc/oleacc_private.h @@ -17,6 +17,7 @@ */
#include "oleacc_classes.h" +#include "servprov.h"
struct win_class_data { const WCHAR *name; diff --git a/dlls/oleacc/tests/main.c b/dlls/oleacc/tests/main.c index 2d6a6c4cc2c..167c2e23a6a 100644 --- a/dlls/oleacc/tests/main.c +++ b/dlls/oleacc/tests/main.c @@ -1419,21 +1419,19 @@ static void check_acc_proxy_service_(IAccessible *acc, int line) HRESULT hr;
hr = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void **)&service); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - if (SUCCEEDED(hr)) - { - hr = IServiceProvider_QueryService(service, &IIS_IsOleaccProxy, &IID_IUnknown, (void **)&unk); - ok(hr == S_OK, "got %#lx\n", hr); - ok(!!unk, "unk == NULL\n"); - ok(iface_cmp(unk, (IUnknown*)acc), "unk != acc\n"); - IUnknown_Release(unk); + ok(hr == S_OK, "got %#lx\n", hr);
- unk = NULL; - hr = IServiceProvider_QueryService(service, &IID_IUnknown, &IID_IUnknown, (void **)&unk); - ok(hr == E_INVALIDARG, "got %#lx\n", hr); - ok(!unk, "unk != NULL\n"); - IServiceProvider_Release(service); - } + hr = IServiceProvider_QueryService(service, &IIS_IsOleaccProxy, &IID_IUnknown, (void **)&unk); + ok(hr == S_OK, "got %#lx\n", hr); + ok(!!unk, "unk == NULL\n"); + ok(iface_cmp(unk, (IUnknown*)acc), "unk != acc\n"); + IUnknown_Release(unk); + + unk = NULL; + hr = IServiceProvider_QueryService(service, &IID_IUnknown, &IID_IUnknown, (void **)&unk); + ok(hr == E_INVALIDARG, "got %#lx\n", hr); + ok(!unk, "unk != NULL\n"); + IServiceProvider_Release(service); }
static void test_CreateStdAccessibleObject_classes(void) diff --git a/dlls/oleacc/window.c b/dlls/oleacc/window.c index 470bfd5b362..e431b6475a8 100644 --- a/dlls/oleacc/window.c +++ b/dlls/oleacc/window.c @@ -30,6 +30,7 @@ typedef struct { IAccessible IAccessible_iface; IOleWindow IOleWindow_iface; IEnumVARIANT IEnumVARIANT_iface; + IServiceProvider IServiceProvider_iface;
LONG ref;
@@ -55,6 +56,8 @@ static HRESULT WINAPI Window_QueryInterface(IAccessible *iface, REFIID riid, voi *ppv = &This->IOleWindow_iface; }else if(IsEqualIID(riid, &IID_IEnumVARIANT)) { *ppv = &This->IEnumVARIANT_iface; + }else if(IsEqualIID(riid, &IID_IServiceProvider)) { + *ppv = &This->IServiceProvider_iface; }else { WARN("no interface: %s\n", debugstr_guid(riid)); *ppv = NULL; @@ -444,6 +447,49 @@ static const IEnumVARIANTVtbl WindowEnumVARIANTVtbl = { Window_EnumVARIANT_Clone };
+static inline Window* impl_from_Window_ServiceProvider(IServiceProvider *iface) +{ + return CONTAINING_RECORD(iface, Window, IServiceProvider_iface); +} + +static HRESULT WINAPI Window_ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + Window *This = impl_from_Window_ServiceProvider(iface); + return IAccessible_QueryInterface(&This->IAccessible_iface, riid, ppv); +} + +static ULONG WINAPI Window_ServiceProvider_AddRef(IServiceProvider *iface) +{ + Window *This = impl_from_Window_ServiceProvider(iface); + return IAccessible_AddRef(&This->IAccessible_iface); +} + +static ULONG WINAPI Window_ServiceProvider_Release(IServiceProvider *iface) +{ + Window *This = impl_from_Window_ServiceProvider(iface); + return IAccessible_Release(&This->IAccessible_iface); +} + +static HRESULT WINAPI Window_ServiceProvider_QueryService(IServiceProvider *iface, REFGUID guid_service, + REFIID riid, void **ppv) +{ + Window *This = impl_from_Window_ServiceProvider(iface); + + TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid_service), debugstr_guid(riid), ppv); + + if (IsEqualIID(guid_service, &IIS_IsOleaccProxy)) + return IAccessible_QueryInterface(&This->IAccessible_iface, riid, ppv); + + return E_INVALIDARG; +} + +static const IServiceProviderVtbl WindowServiceProviderVtbl = { + Window_ServiceProvider_QueryInterface, + Window_ServiceProvider_AddRef, + Window_ServiceProvider_Release, + Window_ServiceProvider_QueryService +}; + static const struct win_class_data classes[] = { {WC_LISTBOXW, 0x10000, TRUE}, {L"#32768", 0x10001, TRUE}, /* menu */ @@ -467,6 +513,7 @@ HRESULT create_window_object(HWND hwnd, const IID *iid, void **obj) window->IAccessible_iface.lpVtbl = &WindowVtbl; window->IOleWindow_iface.lpVtbl = &WindowOleWindowVtbl; window->IEnumVARIANT_iface.lpVtbl = &WindowEnumVARIANTVtbl; + window->IServiceProvider_iface.lpVtbl = &WindowServiceProviderVtbl; window->ref = 1; window->hwnd = hwnd;
Hi Connor,
On 4/25/22 18:18, Connor McAdams wrote:
unk = NULL;
hr = IServiceProvider_QueryService(service, &IID_IUnknown, &IID_IUnknown, (void **)&unk);
ok(hr == E_INVALIDARG, "got %#lx\n", hr);
ok(!unk, "unk != NULL\n");
Is there a reason for setting unk to NULL before the call? On Windows 10 QueryService resets it on failure.
Thanks, Piotr
On Mon, Apr 25, 2022 at 08:34:39PM +0200, Piotr Caban wrote:
Hi Connor,
On 4/25/22 18:18, Connor McAdams wrote:
unk = NULL;
hr = IServiceProvider_QueryService(service, &IID_IUnknown, &IID_IUnknown, (void **)&unk);
ok(hr == E_INVALIDARG, "got %#lx\n", hr);
ok(!unk, "unk != NULL\n");
Is there a reason for setting unk to NULL before the call? On Windows 10 QueryService resets it on failure.
No, I didn't do this for any particular reason. I can set it to a dummy value and check for it being set to NULL and send a v2 if that makes sense.