#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;
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)
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(¶ms, 0xc0, sizeof(params));
+ memset(vars, 0xc0, sizeof(vars));
+ rc = pSHPackDispParams(¶ms, vars, 2, VT_I4, 0xdeadbeef, VT_BSTR, 0xdeadcafe);
+ ok(rc == S_OK, "SHPackDispParams failed: %08x\n", rc);
+
+ rc = pIConnectionPoint_SimpleInvoke(point,0xa1,¶ms);
+ 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");
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();
test_fdsa();
test_GetShellSecurityDescriptor();
test_SHPackDispParams();
+ test_IConnectionPoint();
+ test_SHPropertyBag_ReadLONG();
}