[PATCH] Added IUnknown_ProfferService implementation with tests

Nikolay Sivov nsivov at codeweavers.com
Thu Mar 25 19:21:36 CDT 2010


---
 dlls/shlwapi/ordinal.c       |   45 ++++++++-
 dlls/shlwapi/tests/ordinal.c |  210 ++++++++++++++++++++++++++++++++++++++----
 include/shobjidl.idl         |   16 +++
 3 files changed, 245 insertions(+), 26 deletions(-)

diff --git a/dlls/shlwapi/ordinal.c b/dlls/shlwapi/ordinal.c
index 93bf243..6c3c1d0 100644
--- a/dlls/shlwapi/ordinal.c
+++ b/dlls/shlwapi/ordinal.c
@@ -1533,6 +1533,45 @@ HRESULT WINAPI IUnknown_QueryServiceExec(IUnknown *lpUnknown, REFIID service,
 }
 
 /*************************************************************************
+ *      @	[SHLWAPI.514]
+ *
+ * Calls IProfferService methods to proffer/revoke specified service.
+ *
+ * PARAMS
+ *  lpUnknown [I]  Object to get an IServiceProvider interface from
+ *  service   [I]  Service ID for IProfferService::Proffer/Revoke calls
+ *  pService  [I]  Service to proffer. If NULL ::Revoke is called
+ *  pCookie   [IO] Group ID for IOleCommandTarget::Exec() call
+ *
+ * RETURNS
+ *  Success: S_OK. IProffer method returns S_OK
+ *  Failure: An HRESULT error code
+ *
+ * NOTES
+ *  lpUnknown is expected to support the IServiceProvider interface.
+ */
+HRESULT WINAPI IUnknown_ProfferService(IUnknown *lpUnknown, REFGUID service, IServiceProvider *pService, DWORD *pCookie)
+{
+    IProfferService *proffer;
+    HRESULT hr;
+
+    TRACE("%p %s %p %p\n", lpUnknown, debugstr_guid(service), pService, pCookie);
+
+    hr = IUnknown_QueryService(lpUnknown, &IID_IProfferService, &IID_IProfferService, (void**)&proffer);
+    if (hr == S_OK)
+    {
+        if (pService)
+            hr = IProfferService_ProfferService(proffer, service, pService, pCookie);
+        else
+            hr = IProfferService_RevokeService(proffer, *pCookie);
+
+        IProfferService_Release(proffer);
+    }
+
+    return hr;
+}
+
+/*************************************************************************
  *      @	[SHLWAPI.479]
  *
  * Call an object's UIActivateIO method.
@@ -4462,12 +4501,6 @@ INT WINAPIV ShellMessageBoxWrapW(HINSTANCE hInstance, HWND hWnd, LPCWSTR lpText,
     return ret;
 }
 
-HRESULT WINAPI IUnknown_ProfferService(IUnknown *unk, void *x0, void *x1, void *x2)
-{
-    FIXME("%p %p %p %p\n", unk, x0, x1, x2);
-    return E_NOTIMPL;
-}
-
 /***********************************************************************
  *              ZoneComputePaneSize [SHLWAPI.382]
  */
diff --git a/dlls/shlwapi/tests/ordinal.c b/dlls/shlwapi/tests/ordinal.c
index 2906f69..8f974c9 100644
--- a/dlls/shlwapi/tests/ordinal.c
+++ b/dlls/shlwapi/tests/ordinal.c
@@ -30,6 +30,7 @@
 #include "mlang.h"
 #include "shlwapi.h"
 #include "docobj.h"
+#include "shobjidl.h"
 
 /* Function ptrs for ordinal calls */
 static HMODULE hShlwapi;
@@ -51,6 +52,7 @@ static INT    (WINAPI *pSHFormatDateTimeW)(const FILETIME UNALIGNED*, DWORD*, LP
 static DWORD  (WINAPI *pSHGetObjectCompatFlags)(IUnknown*, const CLSID*);
 static BOOL   (WINAPI *pGUIDFromStringA)(LPSTR, CLSID *);
 static HRESULT (WINAPI *pIUnknown_QueryServiceExec)(IUnknown*, REFIID, const GUID*, DWORD, DWORD, VARIANT*, VARIANT*);
+static HRESULT (WINAPI *pIUnknown_ProfferService)(IUnknown*, REFGUID, IServiceProvider*, DWORD*);
 
 static HMODULE hmlang;
 static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT);
@@ -107,6 +109,33 @@ static void add_call(call_trace_t *ctrace, int id, const void *arg0,
     ctrace->calls[ctrace->count++] = call;
 }
 
+static void ok_trace_(call_trace_t *texpected, call_trace_t *tgot, int line)
+{
+    if (texpected->count == tgot->count)
+    {
+        INT i;
+        /* compare */
+        for (i = 0; i < texpected->count; i++)
+        {
+            call_entry_t *expected = &texpected->calls[i];
+            call_entry_t *got = &tgot->calls[i];
+            INT j;
+
+            ok_(__FILE__, line)(expected->id == got->id, "got different ids %d: %d, %d\n", i+1, expected->id, got->id);
+
+            for (j = 0; j < 5; j++)
+            {
+                ok_(__FILE__, line)(expected->args[j] == got->args[j], "got different args[%d] for %d: %p, %p\n", j, i+1,
+                   expected->args[j], got->args[j]);
+            }
+        }
+    }
+    else
+        ok_(__FILE__, line)(0, "traces length mismatch\n");
+}
+
+#define ok_trace(a, b) ok_trace_(a, b, __LINE__)
+
 static void test_GetAcceptLanguagesA(void)
 {
     static LPCSTR table[] = {"de,en-gb;q=0.7,en;q=0.3",
@@ -2008,7 +2037,14 @@ typedef struct {
     LONG ref;
 } IServiceProviderImpl;
 
+typedef struct {
+    const IProfferServiceVtbl *lpVtbl;
+    LONG ref;
+} IProfferServiceImpl;
+
+
 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
+static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
 
 IServiceProvider* IServiceProviderImpl_Construct(void)
 {
@@ -2021,6 +2057,19 @@ IServiceProvider* IServiceProviderImpl_Construct(void)
     return (IServiceProvider*)obj;
 }
 
+IProfferService* IProfferServiceImpl_Construct(void)
+{
+    IProfferServiceImpl *obj;
+
+    obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
+    obj->lpVtbl = &IProfferServiceImpl_Vtbl;
+    obj->ref = 1;
+
+    return (IProfferService*)obj;
+}
+
+static call_trace_t IUnknown_ProfferService_trace;
+
 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
 {
     IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
@@ -2065,10 +2114,18 @@ static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
 static HRESULT WINAPI IServiceProviderImpl_QueryService(
     IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv)
 {
-    /* natve uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
+    /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
     if (IsEqualIID(riid, &IID_IOleCommandTarget))
+    {
         add_call(&IUnknown_QueryServiceExec_trace, 2, iface, service, &IID_IOleCommandTarget, 0, 0);
-    *ppv = IOleCommandTargetImpl_Construct();
+        *ppv = IOleCommandTargetImpl_Construct();
+    }
+    if (IsEqualIID(riid, &IID_IProfferService))
+    {
+        if (IsEqualIID(service, &IID_IProfferService))
+            add_call(&IUnknown_ProfferService_trace, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
+        *ppv = IProfferServiceImpl_Construct();
+    }
     return S_OK;
 }
 
@@ -2088,7 +2145,6 @@ static void test_IUnknown_QueryServiceExec(void)
     static const GUID dummy_groupid = { 0xbeefbeef };
     call_trace_t trace_expected;
     HRESULT hr;
-    INT i;
 
     /* on <=W2K platforms same ordinal used for another export with different
        prototype, so skipping using this indirect condition */
@@ -2118,31 +2174,143 @@ static void test_IUnknown_QueryServiceExec(void)
     hr = pIUnknown_QueryServiceExec((IUnknown*)provider, &dummy_serviceid, &dummy_groupid, 0x1, 0x2, (void*)0x3, (void*)0x4);
     ok(hr == S_OK, "got 0x%08x\n", hr);
 
-    if (trace_expected.count == IUnknown_QueryServiceExec_trace.count)
+    ok_trace(&trace_expected, &IUnknown_QueryServiceExec_trace);
+
+    free_call_trace(&trace_expected);
+    free_call_trace(&IUnknown_QueryServiceExec_trace);
+
+    IServiceProvider_Release(provider);
+}
+
+
+static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
+{
+    IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
+
+    if (IsEqualIID(riid, &IID_IUnknown) ||
+        IsEqualIID(riid, &IID_IProfferService))
     {
-        /* compare */
-        for (i = 0; i < trace_expected.count; i++)
-        {
-            call_entry_t *expected = &trace_expected.calls[i];
-            call_entry_t *got = &IUnknown_QueryServiceExec_trace.calls[i];
-            INT j;
+        *ppvObj = This;
+    }
+    else if (IsEqualIID(riid, &IID_IServiceProvider))
+    {
+        *ppvObj = IServiceProviderImpl_Construct();
+        add_call(&IUnknown_ProfferService_trace, 1, iface, &IID_IServiceProvider, 0, 0, 0);
+        return S_OK;
+    }
 
-            ok(expected->id == got->id, "got different ids %d: %d, %d\n", i+1, expected->id, got->id);
+    if(*ppvObj)
+    {
+        IUnknown_AddRef(iface);
+        return S_OK;
+    }
 
-            for (j = 0; j < 5; j++)
-            {
-                ok(expected->args[j] == got->args[j], "got different args[%d] for %d: %p, %p\n", j, i+1,
-                   expected->args[j], got->args[j]);
-            }
-        }
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
+{
+    IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
+{
+    IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    if (!ref)
+    {
+        HeapFree(GetProcessHeap(), 0, This);
+        return 0;
     }
-    else
-        ok(0, "traces length mismatch expected %d, got %d\n", trace_expected.count, IUnknown_QueryServiceExec_trace.count);
+    return ref;
+}
+
+static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
+    REFGUID service, IServiceProvider *pService, DWORD *pCookie)
+{
+    add_call(&IUnknown_ProfferService_trace, 3, service, pService, pCookie, 0, 0);
+    return S_OK;
+}
+
+static HRESULT WINAPI IProfferServiceImpl_RevokeService(IProfferService *iface, DWORD cookie)
+{
+    add_call(&IUnknown_ProfferService_trace, 4, (void*)cookie, 0, 0, 0, 0);
+    return S_OK;
+}
+
+static const IProfferServiceVtbl IProfferServiceImpl_Vtbl =
+{
+    IProfferServiceImpl_QueryInterface,
+    IProfferServiceImpl_AddRef,
+    IProfferServiceImpl_Release,
+    IProfferServiceImpl_ProfferService,
+    IProfferServiceImpl_RevokeService
+};
+
+static void test_IUnknown_ProfferService(void)
+{
+    void *test_ptr = (void*)GetProcAddress(hShlwapi, "StrChrNW");
+    IServiceProvider *provider = IServiceProviderImpl_Construct();
+    IProfferService *proff = IProfferServiceImpl_Construct();
+    static const GUID dummy_serviceid = { 0xdeadbeef };
+    call_trace_t trace_expected;
+    HRESULT hr;
+    DWORD cookie;
+
+    /* on <=W2K platforms same ordinal used for another export with different
+       prototype, so skipping using this indirect condition */
+    if (!test_ptr)
+    {
+        win_skip("IUnknown_ProfferService is not available\n");
+        return;
+    }
+
+    /* null source pointer */
+    hr = pIUnknown_ProfferService(NULL, &dummy_serviceid, 0, 0);
+    ok(hr == E_FAIL, "got 0x%08x\n", hr);
+
+    /* expected trace:
+       IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
+         -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
+         -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
+
+         if (service pointer not null):
+             -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
+         else
+             -> IProfferService_RevokeService( proffer, *arg2 );
+    */
+    init_call_trace(&trace_expected);
+
+    add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
+    add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
+    add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
+
+    init_call_trace(&IUnknown_ProfferService_trace);
+    hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
 
+    ok_trace(&trace_expected, &IUnknown_ProfferService_trace);
+    free_call_trace(&IUnknown_ProfferService_trace);
+    free_call_trace(&trace_expected);
+
+    /* same with ::Revoke path */
+    init_call_trace(&trace_expected);
+
+    add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
+    add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
+    add_call(&trace_expected, 4, (void*)cookie, 0, 0, 0, 0);
+
+    init_call_trace(&IUnknown_ProfferService_trace);
+    hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok_trace(&trace_expected, &IUnknown_ProfferService_trace);
+    free_call_trace(&IUnknown_ProfferService_trace);
     free_call_trace(&trace_expected);
-    free_call_trace(&IUnknown_QueryServiceExec_trace);
 
     IServiceProvider_Release(provider);
+    IProfferService_Release(proff);
 }
 
 static void init_pointers(void)
@@ -2165,6 +2333,7 @@ static void init_pointers(void)
     MAKEFUNC(SHGetObjectCompatFlags, 476);
     MAKEFUNC(IUnknown_QueryServiceExec, 484);
     MAKEFUNC(SHPropertyBag_ReadLONG, 496);
+    MAKEFUNC(IUnknown_ProfferService, 514);
 #undef MAKEFUNC
 }
 
@@ -2190,4 +2359,5 @@ START_TEST(ordinal)
     test_SHFormatDateTimeW();
     test_SHGetObjectCompatFlags();
     test_IUnknown_QueryServiceExec();
+    test_IUnknown_ProfferService();
 }
diff --git a/include/shobjidl.idl b/include/shobjidl.idl
index e1bf70b..3781784 100644
--- a/include/shobjidl.idl
+++ b/include/shobjidl.idl
@@ -1529,3 +1529,19 @@ cpp_quote("#define ACDD_VISIBLE   0x0001")
 
     HRESULT ResetEnumerator();
 }
+
+[
+    object,
+    uuid(cb728b20-f786-11ce-92ad-00aa00a74cd0),
+    pointer_default(unique)
+]
+interface IProfferService : IUnknown
+{
+    HRESULT ProfferService(
+        [in] REFGUID service,
+        [in] IServiceProvider *pService,
+        [out] DWORD *pCookie);
+
+    HRESULT RevokeService([in] DWORD cookie);
+}
+
-- 
1.5.6.5


--=-PF/+izTuo36IvbSn1p4i--




More information about the wine-patches mailing list