[SHLWAPI_WINETEST]
[reactos.git] / rostests / winetests / shlwapi / ordinal.c
index 3a50219..22437e2 100755 (executable)
 
 #include <stdio.h>
 
+#define COBJMACROS
 #include "wine/test.h"
 #include "winbase.h"
 #include "winerror.h"
 #include "winuser.h"
 #include "ole2.h"
 #include "oaidl.h"
+#include "ocidl.h"
+#include "mlang.h"
 
 /* Function ptrs for ordinal calls */
 static HMODULE hShlwapi;
@@ -36,138 +39,255 @@ static LPVOID (WINAPI *pSHLockShared)(HANDLE,DWORD);
 static BOOL   (WINAPI *pSHUnlockShared)(LPVOID);
 static BOOL   (WINAPI *pSHFreeShared)(HANDLE,DWORD);
 static HRESULT(WINAPIV *pSHPackDispParams)(DISPPARAMS*,VARIANTARG*,UINT,...);
+static HRESULT(WINAPI *pIConnectionPoint_SimpleInvoke)(IConnectionPoint*,DISPID,DISPPARAMS*);
+static HRESULT(WINAPI *pIConnectionPoint_InvokeWithCancel)(IConnectionPoint*,DISPID,DISPPARAMS*,DWORD,DWORD);
+static HRESULT(WINAPI *pConnectToConnectionPoint)(IUnknown*,REFIID,BOOL,IUnknown*, LPDWORD,IConnectionPoint **);
+static HRESULT(WINAPI *pSHPropertyBag_ReadLONG)(IPropertyBag *,LPCWSTR,LPLONG);
+
+static HMODULE hmlang;
+static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT);
+
+static const CHAR ie_international[] = {
+    'S','o','f','t','w','a','r','e','\\',
+    'M','i','c','r','o','s','o','f','t','\\',
+    'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
+    'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
+static const CHAR acceptlanguage[] = {
+    'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
+
 
 static void test_GetAcceptLanguagesA(void)
-{   HRESULT retval;
-    DWORD buffersize, buffersize2, exactsize;
-    char buffer[100];
+{
+    static LPCSTR table[] = {"de,en-gb;q=0.7,en;q=0.3",
+                             "de,en;q=0.3,en-gb;q=0.7", /* sorting is ignored */
+                             "winetest",    /* content is ignored */
+                             "de-de,de;q=0.5",
+                             "de",
+                             NULL};
+
+    DWORD exactsize;
+    char original[512];
+    char language[32];
+    char buffer[64];
+    HKEY hroot = NULL;
+    LONG res_query = ERROR_SUCCESS;
+    LONG lres;
+    HRESULT hr;
+    DWORD maxlen = sizeof(buffer) - 2;
+    DWORD len;
+    LCID lcid;
+    LPCSTR entry;
+    INT i = 0;
 
     if (!pGetAcceptLanguagesA) {
         win_skip("GetAcceptLanguagesA is not available\n");
-       return;
+        return;
     }
 
-    buffersize = sizeof(buffer);
-    memset(buffer, 0, sizeof(buffer));
-    SetLastError(ERROR_SUCCESS);
-    retval = pGetAcceptLanguagesA( buffer, &buffersize);
-    if (!retval && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
-        win_skip("GetAcceptLanguagesA is not implemented\n");
+    lcid = GetUserDefaultLCID();
+
+    /* Get the original Value */
+    lres = RegOpenKeyA(HKEY_CURRENT_USER, ie_international, &hroot);
+    if (lres) {
+        skip("RegOpenKey(%s) failed: %d\n", ie_international, lres);
         return;
     }
-    trace("GetAcceptLanguagesA: retval %08x, size %08x, buffer (%s),"
-       " last error %u\n", retval, buffersize, buffer, GetLastError());
-    if(retval != S_OK) {
-       trace("GetAcceptLanguagesA: skipping tests\n");
-       return;
-    }
-    ok( (ERROR_NO_IMPERSONATION_TOKEN == GetLastError()) || 
-       (ERROR_CLASS_DOES_NOT_EXIST == GetLastError()) ||
-       (ERROR_PROC_NOT_FOUND == GetLastError()) ||
-       (ERROR_SUCCESS == GetLastError()), "last error set to %u\n", GetLastError());
-    exactsize = strlen(buffer);
-
-    SetLastError(ERROR_SUCCESS);
-    retval = pGetAcceptLanguagesA( NULL, NULL);
-    ok(retval == E_FAIL ||
-       retval == E_INVALIDARG, /* w2k8 */
-       "function result wrong: got %08x; expected E_FAIL\n", retval);
-    ok(ERROR_SUCCESS == GetLastError(), "last error set to %u\n", GetLastError());
-
-    buffersize = sizeof(buffer);
-    SetLastError(ERROR_SUCCESS);
-    retval = pGetAcceptLanguagesA( NULL, &buffersize);
-    ok(retval == E_FAIL ||
-       retval == E_INVALIDARG, /* w2k8 */
-       "function result wrong: got %08x; expected E_FAIL\n", retval);
-    ok(buffersize == sizeof(buffer) ||
-       buffersize == 0, /* w2k8*/
-       "buffersize was changed and is not 0; size (%d))\n", buffersize);
-    ok(ERROR_SUCCESS == GetLastError(), "last error set to %u\n", GetLastError());
-
-    SetLastError(ERROR_SUCCESS);
-    retval = pGetAcceptLanguagesA( buffer, NULL);
-    ok(retval == E_FAIL ||
-       retval == E_INVALIDARG, /* w2k8 */
-       "function result wrong: got %08x; expected E_FAIL\n", retval);
-    ok(ERROR_SUCCESS == GetLastError(), "last error set to %u\n", GetLastError());
-
-    buffersize = 0;
-    memset(buffer, 0, sizeof(buffer));
-    SetLastError(ERROR_SUCCESS);
-    retval = pGetAcceptLanguagesA( buffer, &buffersize);
-    ok(retval == E_FAIL ||
-       retval == E_INVALIDARG, /* w2k8 */
-       "function result wrong: got %08x; expected E_FAIL\n", retval);
-    ok(buffersize == 0,
-       "buffersize wrong(changed) got %08x; expected 0 (2nd parameter; not on Win2k)\n", buffersize);
-    ok(ERROR_SUCCESS == GetLastError(), "last error set to %u\n", GetLastError());
-
-    buffersize = buffersize2 = 1;
-    memset(buffer, 0, sizeof(buffer));
-    SetLastError(ERROR_SUCCESS);
-    retval = pGetAcceptLanguagesA( buffer, &buffersize);
-    switch(retval) {
-       case 0L:
-            if(buffersize == exactsize) {
-            ok( (ERROR_SUCCESS == GetLastError()) ||
-               (ERROR_PROC_NOT_FOUND == GetLastError()) || (ERROR_NO_IMPERSONATION_TOKEN == GetLastError()),
-                "last error wrong: got %u; expected ERROR_SUCCESS(NT4)/"
-               "ERROR_PROC_NOT_FOUND(NT4)/ERROR_NO_IMPERSONATION_TOKEN(XP)\n", GetLastError());
-            ok(exactsize == strlen(buffer),
-                 "buffer content (length) wrong: got %08x, expected %08x\n", lstrlenA(buffer), exactsize);
-            } else if((buffersize +1) == buffersize2) {
-                ok(ERROR_SUCCESS == GetLastError(),
-                    "last error wrong: got %u; expected ERROR_SUCCESS\n", GetLastError());
-                ok(buffersize == strlen(buffer),
-                    "buffer content (length) wrong: got %08x, expected %08x\n", lstrlenA(buffer), buffersize);
-            } else
-                ok( 0, "retval %08x, size %08x, buffer (%s), last error %u\n",
-                    retval, buffersize, buffer, GetLastError());
-            break;
-       case E_INVALIDARG:
-            ok(buffersize == 0,
-               "buffersize wrong: got %08x, expected 0 (2nd parameter;Win2k)\n", buffersize);
-            ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
-               "last error wrong: got %u; expected ERROR_INSUFFICIENT_BUFFER\n", GetLastError());
-            ok(buffersize2 == strlen(buffer),
-               "buffer content (length) wrong: got %08x, expected %08x\n", lstrlenA(buffer), buffersize2);
-            break;
-        default:
-            ok( 0, "retval %08x, size %08x, buffer (%s), last error %u\n",
-                retval, buffersize, buffer, GetLastError());
-            break;
-    }
-
-    buffersize = buffersize2 = exactsize;
-    memset(buffer, 0, sizeof(buffer));
-    SetLastError(ERROR_SUCCESS);
-    retval = pGetAcceptLanguagesA( buffer, &buffersize);
-    switch(retval) {
-       case 0L:
-            ok(ERROR_SUCCESS == GetLastError(),
-                 "last error wrong: got %u; expected ERROR_SUCCESS\n", GetLastError());
-            if((buffersize == exactsize) /* XP */ ||
-               ((buffersize +1)== exactsize) /* 98 */)
-                ok(buffersize == strlen(buffer),
-                    "buffer content (length) wrong: got %08x, expected %08x\n", lstrlenA(buffer), buffersize);
-            else
-                ok( 0, "retval %08x, size %08x, buffer (%s), last error %u\n",
-                    retval, buffersize, buffer, GetLastError());
-            break;
-       case E_INVALIDARG:
-            ok(buffersize == 0,
-               "buffersize wrong: got %08x, expected 0 (2nd parameter;Win2k)\n", buffersize);
-            ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
-               "last error wrong: got %u; expected ERROR_INSUFFICIENT_BUFFER\n", GetLastError());
-            ok(buffersize2 == strlen(buffer),
-               "buffer content (length) wrong: got %08x, expected %08x\n", lstrlenA(buffer), buffersize2);
-            break;
-        default:
-            ok( 0, "retval %08x, size %08x, buffer (%s), last error %u\n",
-                retval, buffersize, buffer, GetLastError());
-            break;
+    len = sizeof(original);
+    original[0] = 0;
+    res_query = RegQueryValueExA(hroot, acceptlanguage, 0, NULL, (PBYTE)original, &len);
+
+    RegDeleteValue(hroot, acceptlanguage);
+
+    /* Some windows versions use "lang-COUNTRY" as default */
+    memset(language, 0, sizeof(language));
+    len = GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, language, sizeof(language));
+
+    if (len) {
+        lstrcat(language, "-");
+        memset(buffer, 0, sizeof(buffer));
+        len = GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, buffer, sizeof(buffer) - len - 1);
+        lstrcat(language, buffer);
+    }
+    else
+    {
+        /* LOCALE_SNAME has additional parts in some languages. Try only as last chance */
+        memset(language, 0, sizeof(language));
+        len = GetLocaleInfoA(lcid, LOCALE_SNAME, language, sizeof(language));
+    }
+
+    /* get the default value */
+    len = maxlen;
+    memset(buffer, '#', maxlen);
+    buffer[maxlen] = 0;
+    hr = pGetAcceptLanguagesA( buffer, &len);
+
+    if (hr != S_OK) {
+        win_skip("GetAcceptLanguagesA failed with 0x%x\n", hr);
+        goto restore_original;
+    }
+
+    if (lstrcmpA(buffer, language)) {
+        /* some windows versions use "lang" or "lang-country" as default */
+        language[0] = 0;
+        if (pLcidToRfc1766A) {
+            hr = pLcidToRfc1766A(lcid, language, sizeof(language));
+            ok(hr == S_OK, "LcidToRfc1766A returned 0x%x and %s\n", hr, language);
+        }
+    }
+
+    ok(!lstrcmpA(buffer, language),
+        "have '%s' (searching for '%s')\n", language, buffer);
+
+    if (lstrcmpA(buffer, language)) {
+        win_skip("no more ideas, how to build the default language '%s'\n", buffer);
+        goto restore_original;
+    }
+
+    trace("detected default: %s\n", language);
+    while ((entry = table[i])) {
+
+        exactsize = lstrlenA(entry);
+
+        lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) entry, exactsize + 1);
+        ok(!lres, "got %d for RegSetValueExA: %s\n", lres, entry);
+
+        /* len includes space for the terminating 0 before vista/w2k8 */
+        len = exactsize + 2;
+        memset(buffer, '#', maxlen);
+        buffer[maxlen] = 0;
+        hr = pGetAcceptLanguagesA( buffer, &len);
+        ok(((hr == E_INVALIDARG) && (len == 0)) ||
+            (SUCCEEDED(hr) &&
+            ((len == exactsize) || (len == exactsize+1)) &&
+            !lstrcmpA(buffer, entry)),
+            "+2_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
+
+        len = exactsize + 1;
+        memset(buffer, '#', maxlen);
+        buffer[maxlen] = 0;
+        hr = pGetAcceptLanguagesA( buffer, &len);
+        ok(((hr == E_INVALIDARG) && (len == 0)) ||
+            (SUCCEEDED(hr) &&
+            ((len == exactsize) || (len == exactsize+1)) &&
+            !lstrcmpA(buffer, entry)),
+            "+1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
+
+        len = exactsize;
+        memset(buffer, '#', maxlen);
+        buffer[maxlen] = 0;
+        hr = pGetAcceptLanguagesA( buffer, &len);
+
+        /* There is no space for the string in the registry.
+           When the buffer is large enough, the default language is returned
+
+           When the buffer is to small for that fallback, win7_32 and w2k8_64
+           and above fail with HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), but
+           recent os succeed and return a partial result while
+           older os succeed and overflow the buffer */
+
+        ok(((hr == E_INVALIDARG) && (len == 0)) ||
+            (((hr == S_OK) && !lstrcmpA(buffer, language)  && (len == lstrlenA(language))) ||
+            ((hr == S_OK) && !memcmp(buffer, language, len)) ||
+            ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
+            "==_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
+
+        if (exactsize > 1) {
+            len = exactsize - 1;
+            memset(buffer, '#', maxlen);
+            buffer[maxlen] = 0;
+            hr = pGetAcceptLanguagesA( buffer, &len);
+            ok(((hr == E_INVALIDARG) && (len == 0)) ||
+                (((hr == S_OK) && !lstrcmpA(buffer, language)  && (len == lstrlenA(language))) ||
+                ((hr == S_OK) && !memcmp(buffer, language, len)) ||
+                ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
+                "-1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
+        }
+
+        len = 1;
+        memset(buffer, '#', maxlen);
+        buffer[maxlen] = 0;
+        hr = pGetAcceptLanguagesA( buffer, &len);
+        ok(((hr == E_INVALIDARG) && (len == 0)) ||
+            (((hr == S_OK) && !lstrcmpA(buffer, language)  && (len == lstrlenA(language))) ||
+            ((hr == S_OK) && !memcmp(buffer, language, len)) ||
+            ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len)),
+            "=1_#%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
+
+        len = maxlen;
+        hr = pGetAcceptLanguagesA( NULL, &len);
+
+        /* w2k3 and below: E_FAIL and untouched len,
+           since w2k8: S_OK and needed size (excluding 0) */
+        ok( ((hr == S_OK) && (len == exactsize)) ||
+            ((hr == E_FAIL) && (len == maxlen)),
+            "NULL,max #%d: got 0x%x with %d and %s\n", i, hr, len, buffer);
+
+        i++;
+    }
+
+    /* without a value in the registry, a default language is returned */
+    RegDeleteValue(hroot, acceptlanguage);
+
+    len = maxlen;
+    memset(buffer, '#', maxlen);
+    buffer[maxlen] = 0;
+    hr = pGetAcceptLanguagesA( buffer, &len);
+    ok( ((hr == S_OK) && (len == lstrlenA(language))),
+        "max: got 0x%x with %d and %s (expected S_OK with %d and '%s'\n",
+        hr, len, buffer, lstrlenA(language), language);
+
+    len = 2;
+    memset(buffer, '#', maxlen);
+    buffer[maxlen] = 0;
+    hr = pGetAcceptLanguagesA( buffer, &len);
+    ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
+        ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len),
+        "=2: got 0x%x with %d and %s\n", hr, len, buffer);
+
+    len = 1;
+    memset(buffer, '#', maxlen);
+    buffer[maxlen] = 0;
+    hr = pGetAcceptLanguagesA( buffer, &len);
+    /* When the buffer is to small, win7_32 and w2k8_64 and above fail with
+       HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), other versions suceed
+       and return a partial 0 terminated result while other versions
+       fail with E_INVALIDARG and return a partial unterminated result */
+    ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
+        ((hr == __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) && !len),
+        "=1: got 0x%x with %d and %s\n", hr, len, buffer);
+
+    len = 0;
+    memset(buffer, '#', maxlen);
+    buffer[maxlen] = 0;
+    hr = pGetAcceptLanguagesA( buffer, &len);
+    /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
+    ok((hr == E_FAIL) || (hr == E_INVALIDARG),
+        "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
+
+    memset(buffer, '#', maxlen);
+    buffer[maxlen] = 0;
+    hr = pGetAcceptLanguagesA( buffer, NULL);
+    /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
+    ok((hr == E_FAIL) || (hr == E_INVALIDARG),
+        "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
+
+
+    hr = pGetAcceptLanguagesA( NULL, NULL);
+    /* w2k3 and below: E_FAIL, since w2k8: E_INVALIDARG */
+    ok((hr == E_FAIL) || (hr == E_INVALIDARG),
+        "got 0x%x (expected E_FAIL or E_INVALIDARG)\n", hr);
+
+restore_original:
+    if (!res_query) {
+        len = lstrlenA(original);
+        lres = RegSetValueExA(hroot, acceptlanguage, 0, REG_SZ, (const BYTE *) original, len ? len + 1: 0);
+        ok(!lres, "RegSetValueEx(%s) failed: %d\n", original, lres);
+    }
+    else
+    {
+        RegDeleteValue(hroot, acceptlanguage);
     }
+    RegCloseKey(hroot);
 }
 
 static void test_SHSearchMapInt(void)
@@ -511,6 +631,772 @@ static void test_SHPackDispParams(void)
     ok(V_BSTR(vars+3) == (void*)0xdeadbeef, "V_BSTR(vars[3]) = %p\n", V_BSTR(vars+3));
 }
 
+typedef struct _disp
+{
+    const IDispatchVtbl *vtbl;
+    LONG   refCount;
+} Disp;
+
+typedef struct _contain
+{
+    const IConnectionPointContainerVtbl *vtbl;
+    LONG   refCount;
+
+    UINT  ptCount;
+    IConnectionPoint **pt;
+} Contain;
+
+typedef struct _cntptn
+{
+    const IConnectionPointVtbl *vtbl;
+    LONG refCount;
+
+    Contain *container;
+    GUID  id;
+    UINT  sinkCount;
+    IUnknown **sink;
+} ConPt;
+
+typedef struct _enum
+{
+    const IEnumConnectionsVtbl *vtbl;
+    LONG   refCount;
+
+    UINT idx;
+    ConPt *pt;
+} EnumCon;
+
+typedef struct _enumpt
+{
+    const IEnumConnectionPointsVtbl *vtbl;
+    LONG   refCount;
+
+    int idx;
+    Contain *container;
+} EnumPt;
+
+
+static HRESULT WINAPI Disp_QueryInterface(
+        IDispatch* This,
+        REFIID riid,
+        void **ppvObject)
+{
+    *ppvObject = NULL;
+
+    if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch))
+    {
+        *ppvObject = This;
+    }
+
+    if (*ppvObject)
+    {
+        IUnknown_AddRef(This);
+        return S_OK;
+    }
+
+    trace("no interface\n");
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI Disp_AddRef(IDispatch* This)
+{
+    Disp *iface = (Disp*)This;
+    return InterlockedIncrement(&iface->refCount);
+}
+
+static ULONG WINAPI Disp_Release(IDispatch* This)
+{
+    Disp *iface = (Disp*)This;
+    ULONG ret;
+
+    ret = InterlockedDecrement(&iface->refCount);
+    if (ret == 0)
+        HeapFree(GetProcessHeap(),0,This);
+    return ret;
+}
+
+static HRESULT WINAPI Disp_GetTypeInfoCount(
+        IDispatch* This,
+        UINT *pctinfo)
+{
+    return ERROR_SUCCESS;
+}
+
+static HRESULT WINAPI Disp_GetTypeInfo(
+        IDispatch* This,
+        UINT iTInfo,
+        LCID lcid,
+        ITypeInfo **ppTInfo)
+{
+    return ERROR_SUCCESS;
+}
+
+static HRESULT WINAPI Disp_GetIDsOfNames(
+        IDispatch* This,
+        REFIID riid,
+        LPOLESTR *rgszNames,
+        UINT cNames,
+        LCID lcid,
+        DISPID *rgDispId)
+{
+    return ERROR_SUCCESS;
+}
+
+static HRESULT WINAPI Disp_Invoke(
+        IDispatch* This,
+        DISPID dispIdMember,
+        REFIID riid,
+        LCID lcid,
+        WORD wFlags,
+        DISPPARAMS *pDispParams,
+        VARIANT *pVarResult,
+        EXCEPINFO *pExcepInfo,
+        UINT *puArgErr)
+{
+    trace("%p %x %p %x %x %p %p %p %p\n",This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
+
+    ok(dispIdMember == 0xa0 || dispIdMember == 0xa1, "Unknown dispIdMember\n");
+    ok(pDispParams != NULL, "Invoked with NULL pDispParams\n");
+    ok(wFlags == DISPATCH_METHOD, "Wrong flags %x\n",wFlags);
+    ok(lcid == 0,"Wrong lcid %x\n",lcid);
+    if (dispIdMember == 0xa0)
+    {
+        ok(pDispParams->cArgs == 0, "params.cArgs = %d\n", pDispParams->cArgs);
+        ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
+        ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
+        ok(pDispParams->rgvarg == NULL, "params.rgvarg = %p\n", pDispParams->rgvarg);
+    }
+    else if (dispIdMember == 0xa1)
+    {
+        ok(pDispParams->cArgs == 2, "params.cArgs = %d\n", pDispParams->cArgs);
+        ok(pDispParams->cNamedArgs == 0, "params.cNamedArgs = %d\n", pDispParams->cArgs);
+        ok(pDispParams->rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
+        ok(V_VT(pDispParams->rgvarg) == VT_BSTR, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg));
+        ok(V_I4(pDispParams->rgvarg) == 0xdeadcafe , "failed %p\n", V_BSTR(pDispParams->rgvarg));
+        ok(V_VT(pDispParams->rgvarg+1) == VT_I4, "V_VT(var) = %d\n", V_VT(pDispParams->rgvarg+1));
+        ok(V_I4(pDispParams->rgvarg+1) == 0xdeadbeef, "failed %x\n", V_I4(pDispParams->rgvarg+1));
+    }
+
+    return ERROR_SUCCESS;
+}
+
+static const IDispatchVtbl disp_vtbl = {
+    Disp_QueryInterface,
+    Disp_AddRef,
+    Disp_Release,
+
+    Disp_GetTypeInfoCount,
+    Disp_GetTypeInfo,
+    Disp_GetIDsOfNames,
+    Disp_Invoke
+};
+
+static HRESULT WINAPI Enum_QueryInterface(
+        IEnumConnections* This,
+        REFIID riid,
+        void **ppvObject)
+{
+    *ppvObject = NULL;
+
+    if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnections))
+    {
+        *ppvObject = This;
+    }
+
+    if (*ppvObject)
+    {
+        IUnknown_AddRef(This);
+        return S_OK;
+    }
+
+    trace("no interface\n");
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI Enum_AddRef(IEnumConnections* This)
+{
+    EnumCon *iface = (EnumCon*)This;
+    return InterlockedIncrement(&iface->refCount);
+}
+
+static ULONG WINAPI Enum_Release(IEnumConnections* This)
+{
+    EnumCon *iface = (EnumCon*)This;
+    ULONG ret;
+
+    ret = InterlockedDecrement(&iface->refCount);
+    if (ret == 0)
+        HeapFree(GetProcessHeap(),0,This);
+    return ret;
+}
+
+static HRESULT WINAPI Enum_Next(
+        IEnumConnections* This,
+        ULONG cConnections,
+        LPCONNECTDATA rgcd,
+        ULONG *pcFetched)
+{
+    EnumCon *iface = (EnumCon*)This;
+
+    if (cConnections > 0 && iface->idx < iface->pt->sinkCount)
+    {
+        rgcd->pUnk = iface->pt->sink[iface->idx];
+        IUnknown_AddRef(iface->pt->sink[iface->idx]);
+        rgcd->dwCookie=0xff;
+        if (pcFetched)
+            *pcFetched = 1;
+        iface->idx++;
+        return S_OK;
+    }
+
+    return E_FAIL;
+}
+
+static HRESULT WINAPI Enum_Skip(
+        IEnumConnections* This,
+        ULONG cConnections)
+{
+    return E_FAIL;
+}
+
+static HRESULT WINAPI Enum_Reset(
+        IEnumConnections* This)
+{
+    return E_FAIL;
+}
+
+static HRESULT WINAPI Enum_Clone(
+        IEnumConnections* This,
+        IEnumConnections **ppEnum)
+{
+    return E_FAIL;
+}
+
+static const IEnumConnectionsVtbl enum_vtbl = {
+
+    Enum_QueryInterface,
+    Enum_AddRef,
+    Enum_Release,
+    Enum_Next,
+    Enum_Skip,
+    Enum_Reset,
+    Enum_Clone
+};
+
+static HRESULT WINAPI ConPt_QueryInterface(
+        IConnectionPoint* This,
+        REFIID riid,
+        void **ppvObject)
+{
+    *ppvObject = NULL;
+
+    if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPoint))
+    {
+        *ppvObject = This;
+    }
+
+    if (*ppvObject)
+    {
+        IUnknown_AddRef(This);
+        return S_OK;
+    }
+
+    trace("no interface\n");
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ConPt_AddRef(
+        IConnectionPoint* This)
+{
+    ConPt *iface = (ConPt*)This;
+    return InterlockedIncrement(&iface->refCount);
+}
+
+static ULONG WINAPI ConPt_Release(
+        IConnectionPoint* This)
+{
+    ConPt *iface = (ConPt*)This;
+    ULONG ret;
+
+    ret = InterlockedDecrement(&iface->refCount);
+    if (ret == 0)
+    {
+        if (iface->sinkCount > 0)
+        {
+            int i;
+            for (i = 0; i < iface->sinkCount; i++)
+            {
+                if (iface->sink[i])
+                    IUnknown_Release(iface->sink[i]);
+            }
+            HeapFree(GetProcessHeap(),0,iface->sink);
+        }
+        HeapFree(GetProcessHeap(),0,This);
+    }
+    return ret;
+}
+
+static HRESULT WINAPI ConPt_GetConnectionInterface(
+        IConnectionPoint* This,
+        IID *pIID)
+{
+    static int i = 0;
+    ConPt *iface = (ConPt*)This;
+    if (i==0)
+    {
+        i++;
+        return E_FAIL;
+    }
+    else
+        memcpy(pIID,&iface->id,sizeof(GUID));
+    return S_OK;
+}
+
+static HRESULT WINAPI ConPt_GetConnectionPointContainer(
+        IConnectionPoint* This,
+        IConnectionPointContainer **ppCPC)
+{
+    ConPt *iface = (ConPt*)This;
+
+    *ppCPC = (IConnectionPointContainer*)iface->container;
+    return S_OK;
+}
+
+static HRESULT WINAPI ConPt_Advise(
+        IConnectionPoint* This,
+        IUnknown *pUnkSink,
+        DWORD *pdwCookie)
+{
+    ConPt *iface = (ConPt*)This;
+
+    if (iface->sinkCount == 0)
+        iface->sink = HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
+    else
+        iface->sink = HeapReAlloc(GetProcessHeap(),0,iface->sink,sizeof(IUnknown*)*(iface->sinkCount+1));
+    iface->sink[iface->sinkCount] = pUnkSink;
+    IUnknown_AddRef(pUnkSink);
+    iface->sinkCount++;
+    *pdwCookie = iface->sinkCount;
+    return S_OK;
+}
+
+static HRESULT WINAPI ConPt_Unadvise(
+        IConnectionPoint* This,
+        DWORD dwCookie)
+{
+    ConPt *iface = (ConPt*)This;
+
+    if (dwCookie > iface->sinkCount)
+        return E_FAIL;
+    else
+    {
+        IUnknown_Release(iface->sink[dwCookie-1]);
+        iface->sink[dwCookie-1] = NULL;
+    }
+    return S_OK;
+}
+
+static HRESULT WINAPI ConPt_EnumConnections(
+        IConnectionPoint* This,
+        IEnumConnections **ppEnum)
+{
+    EnumCon *ec;
+
+    ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon));
+    ec->vtbl = &enum_vtbl;
+    ec->refCount = 1;
+    ec->pt = (ConPt*)This;
+    ec->idx = 0;
+    *ppEnum = (IEnumConnections*)ec;
+
+    return S_OK;
+}
+
+static const IConnectionPointVtbl point_vtbl = {
+    ConPt_QueryInterface,
+    ConPt_AddRef,
+    ConPt_Release,
+
+    ConPt_GetConnectionInterface,
+    ConPt_GetConnectionPointContainer,
+    ConPt_Advise,
+    ConPt_Unadvise,
+    ConPt_EnumConnections
+};
+
+static HRESULT WINAPI EnumPt_QueryInterface(
+        IEnumConnectionPoints* This,
+        REFIID riid,
+        void **ppvObject)
+{
+    *ppvObject = NULL;
+
+    if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumConnectionPoints))
+    {
+        *ppvObject = This;
+    }
+
+    if (*ppvObject)
+    {
+        IUnknown_AddRef(This);
+        return S_OK;
+    }
+
+    trace("no interface\n");
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI EnumPt_AddRef(IEnumConnectionPoints* This)
+{
+    EnumPt *iface = (EnumPt*)This;
+    return InterlockedIncrement(&iface->refCount);
+}
+
+static ULONG WINAPI EnumPt_Release(IEnumConnectionPoints* This)
+{
+    EnumPt *iface = (EnumPt*)This;
+    ULONG ret;
+
+    ret = InterlockedDecrement(&iface->refCount);
+    if (ret == 0)
+        HeapFree(GetProcessHeap(),0,This);
+    return ret;
+}
+
+static HRESULT WINAPI EnumPt_Next(
+        IEnumConnectionPoints* This,
+        ULONG cConnections,
+        IConnectionPoint **rgcd,
+        ULONG *pcFetched)
+{
+    EnumPt *iface = (EnumPt*)This;
+
+    if (cConnections > 0 && iface->idx < iface->container->ptCount)
+    {
+        *rgcd = iface->container->pt[iface->idx];
+        IUnknown_AddRef(iface->container->pt[iface->idx]);
+        if (pcFetched)
+            *pcFetched = 1;
+        iface->idx++;
+        return S_OK;
+    }
+
+    return E_FAIL;
+}
+
+static HRESULT WINAPI EnumPt_Skip(
+        IEnumConnectionPoints* This,
+        ULONG cConnections)
+{
+    return E_FAIL;
+}
+
+static HRESULT WINAPI EnumPt_Reset(
+        IEnumConnectionPoints* This)
+{
+    return E_FAIL;
+}
+
+static HRESULT WINAPI EnumPt_Clone(
+        IEnumConnectionPoints* This,
+        IEnumConnectionPoints **ppEnumPt)
+{
+    return E_FAIL;
+}
+
+static const IEnumConnectionPointsVtbl enumpt_vtbl = {
+
+    EnumPt_QueryInterface,
+    EnumPt_AddRef,
+    EnumPt_Release,
+    EnumPt_Next,
+    EnumPt_Skip,
+    EnumPt_Reset,
+    EnumPt_Clone
+};
+
+static HRESULT WINAPI Contain_QueryInterface(
+        IConnectionPointContainer* This,
+        REFIID riid,
+        void **ppvObject)
+{
+    *ppvObject = NULL;
+
+    if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IConnectionPointContainer))
+    {
+        *ppvObject = This;
+    }
+
+    if (*ppvObject)
+    {
+        IUnknown_AddRef(This);
+        return S_OK;
+    }
+
+    trace("no interface\n");
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI Contain_AddRef(
+        IConnectionPointContainer* This)
+{
+    Contain *iface = (Contain*)This;
+    return InterlockedIncrement(&iface->refCount);
+}
+
+static ULONG WINAPI Contain_Release(
+        IConnectionPointContainer* This)
+{
+    Contain *iface = (Contain*)This;
+    ULONG ret;
+
+    ret = InterlockedDecrement(&iface->refCount);
+    if (ret == 0)
+    {
+        if (iface->ptCount > 0)
+        {
+            int i;
+            for (i = 0; i < iface->ptCount; i++)
+                IUnknown_Release(iface->pt[i]);
+            HeapFree(GetProcessHeap(),0,iface->pt);
+        }
+        HeapFree(GetProcessHeap(),0,This);
+    }
+    return ret;
+}
+
+static HRESULT WINAPI Contain_EnumConnectionPoints(
+        IConnectionPointContainer* This,
+        IEnumConnectionPoints **ppEnum)
+{
+    EnumPt *ec;
+
+    ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt));
+    ec->vtbl = &enumpt_vtbl;
+    ec->refCount = 1;
+    ec->idx= 0;
+    ec->container = (Contain*)This;
+    *ppEnum = (IEnumConnectionPoints*)ec;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI Contain_FindConnectionPoint(
+        IConnectionPointContainer* This,
+        REFIID riid,
+        IConnectionPoint **ppCP)
+{
+    Contain *iface = (Contain*)This;
+    ConPt *pt;
+
+    if (!IsEqualIID(riid, &IID_NULL) || iface->ptCount ==0)
+    {
+        pt = HeapAlloc(GetProcessHeap(),0,sizeof(ConPt));
+        pt->vtbl = &point_vtbl;
+        pt->refCount = 1;
+        pt->sinkCount = 0;
+        pt->sink = NULL;
+        pt->container = iface;
+        pt->id = IID_IDispatch;
+
+        if (iface->ptCount == 0)
+            iface->pt =HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
+        else
+            iface->pt = HeapReAlloc(GetProcessHeap(),0,iface->pt,sizeof(IUnknown*)*(iface->ptCount+1));
+        iface->pt[iface->ptCount] = (IConnectionPoint*)pt;
+        iface->ptCount++;
+
+        *ppCP = (IConnectionPoint*)pt;
+    }
+    else
+    {
+        *ppCP = iface->pt[0];
+        IUnknown_AddRef((IUnknown*)*ppCP);
+    }
+
+    return S_OK;
+}
+
+static const IConnectionPointContainerVtbl contain_vtbl = {
+    Contain_QueryInterface,
+    Contain_AddRef,
+    Contain_Release,
+
+    Contain_EnumConnectionPoints,
+    Contain_FindConnectionPoint
+};
+
+static void test_IConnectionPoint(void)
+{
+    HRESULT rc;
+    ULONG ref;
+    IConnectionPoint *point;
+    Contain *container;
+    Disp *dispatch;
+    DWORD cookie = 0xffffffff;
+    DISPPARAMS params;
+    VARIANT vars[10];
+
+    if (!pIConnectionPoint_SimpleInvoke || !pConnectToConnectionPoint)
+    {
+        win_skip("IConnectionPoint Apis not present\n");
+        return;
+    }
+
+    container = HeapAlloc(GetProcessHeap(),0,sizeof(Contain));
+    container->vtbl = &contain_vtbl;
+    container->refCount = 1;
+    container->ptCount = 0;
+    container->pt = NULL;
+
+    dispatch = HeapAlloc(GetProcessHeap(),0,sizeof(Disp));
+    dispatch->vtbl = &disp_vtbl;
+    dispatch->refCount = 1;
+
+    rc = pConnectToConnectionPoint((IUnknown*)dispatch, &IID_NULL, TRUE, (IUnknown*)container, &cookie, &point);
+    ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
+    ok(point != NULL, "returned ConnectionPoint is NULL\n");
+    ok(cookie != 0xffffffff, "invalid cookie returned\n");
+
+    rc = pIConnectionPoint_SimpleInvoke(point,0xa0,NULL);
+    ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
+
+    if (pSHPackDispParams)
+    {
+        memset(&params, 0xc0, sizeof(params));
+        memset(vars, 0xc0, sizeof(vars));
+        rc = pSHPackDispParams(&params, vars, 2, VT_I4, 0xdeadbeef, VT_BSTR, 0xdeadcafe);
+        ok(rc == S_OK, "SHPackDispParams failed: %08x\n", rc);
+
+        rc = pIConnectionPoint_SimpleInvoke(point,0xa1,&params);
+        ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
+    }
+    else
+        win_skip("pSHPackDispParams not present\n");
+
+    rc = pConnectToConnectionPoint(NULL, &IID_NULL, FALSE, (IUnknown*)container, &cookie, NULL);
+    ok(rc == S_OK, "pConnectToConnectionPoint failed with %x\n",rc);
+
+/* MSDN says this should be required but it crashs on XP
+    IUnknown_Release(point);
+*/
+    ref = IUnknown_Release((IUnknown*)container);
+    ok(ref == 0, "leftover IConnectionPointContainer reference %i\n",ref);
+    ref = IUnknown_Release((IUnknown*)dispatch);
+    ok(ref == 0, "leftover IDispatch reference %i\n",ref);
+}
+
+typedef struct _propbag
+{
+    const IPropertyBagVtbl *vtbl;
+    LONG   refCount;
+
+} PropBag;
+
+
+static HRESULT WINAPI Prop_QueryInterface(
+        IPropertyBag* This,
+        REFIID riid,
+        void **ppvObject)
+{
+    *ppvObject = NULL;
+
+    if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPropertyBag))
+    {
+        *ppvObject = This;
+    }
+
+    if (*ppvObject)
+    {
+        IUnknown_AddRef(This);
+        return S_OK;
+    }
+
+    trace("no interface\n");
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI Prop_AddRef(
+        IPropertyBag* This)
+{
+    PropBag *iface = (PropBag*)This;
+    return InterlockedIncrement(&iface->refCount);
+}
+
+static ULONG WINAPI Prop_Release(
+        IPropertyBag* This)
+{
+    PropBag *iface = (PropBag*)This;
+    ULONG ret;
+
+    ret = InterlockedDecrement(&iface->refCount);
+    if (ret == 0)
+        HeapFree(GetProcessHeap(),0,This);
+    return ret;
+}
+
+static HRESULT WINAPI Prop_Read(
+        IPropertyBag* This,
+        LPCOLESTR pszPropName,
+        VARIANT *pVar,
+        IErrorLog *pErrorLog)
+{
+    V_VT(pVar) = VT_BLOB|VT_BYREF;
+    V_BYREF(pVar) = (LPVOID)0xdeadcafe;
+    return S_OK;
+}
+
+static HRESULT WINAPI Prop_Write(
+        IPropertyBag* This,
+        LPCOLESTR pszPropName,
+        VARIANT *pVar)
+{
+    return S_OK;
+}
+
+
+static const IPropertyBagVtbl prop_vtbl = {
+    Prop_QueryInterface,
+    Prop_AddRef,
+    Prop_Release,
+
+    Prop_Read,
+    Prop_Write
+};
+
+static void test_SHPropertyBag_ReadLONG(void)
+{
+    PropBag *pb;
+    HRESULT rc;
+    LONG out;
+    static const WCHAR szName1[] = {'n','a','m','e','1',0};
+
+    if (!pSHPropertyBag_ReadLONG)
+    {
+        win_skip("SHPropertyBag_ReadLONG not present\n");
+        return;
+    }
+
+    pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag));
+    pb->refCount = 1;
+    pb->vtbl = &prop_vtbl;
+
+    out = 0xfeedface;
+    rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out);
+    ok(rc == E_INVALIDARG || broken(rc == 0), "incorrect return %x\n",rc);
+    ok(out == 0xfeedface, "value should not have changed\n");
+    rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, NULL, &out);
+    ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
+    ok(out == 0xfeedface, "value should not have changed\n");
+    rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, szName1, NULL);
+    ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
+    ok(out == 0xfeedface, "value should not have changed\n");
+    rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, szName1, &out);
+    ok(rc == DISP_E_BADVARTYPE || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
+    ok(out == 0xfeedface  || broken(out == 0xfeedfa00), "value should not have changed %x\n",out);
+    IUnknown_Release((IUnknown*)pb);
+}
+
 START_TEST(ordinal)
 {
   hShlwapi = GetModuleHandleA("shlwapi.dll");
@@ -522,6 +1408,13 @@ START_TEST(ordinal)
   pSHUnlockShared=(void*)GetProcAddress(hShlwapi,(char*)9);
   pSHFreeShared=(void*)GetProcAddress(hShlwapi,(char*)10);
   pSHPackDispParams=(void*)GetProcAddress(hShlwapi,(char*)282);
+  pIConnectionPoint_SimpleInvoke=(void*)GetProcAddress(hShlwapi,(char*)284);
+  pIConnectionPoint_InvokeWithCancel=(void*)GetProcAddress(hShlwapi,(char*)283);
+  pConnectToConnectionPoint=(void*)GetProcAddress(hShlwapi,(char*)168);
+  pSHPropertyBag_ReadLONG=(void*)GetProcAddress(hShlwapi,(char*)496);
+
+  hmlang = LoadLibraryA("mlang.dll");
+  pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A");
 
   test_GetAcceptLanguagesA();
   test_SHSearchMapInt();
@@ -529,4 +1422,6 @@ START_TEST(ordinal)
   test_fdsa();
   test_GetShellSecurityDescriptor();
   test_SHPackDispParams();
+  test_IConnectionPoint();
+  test_SHPropertyBag_ReadLONG();
 }