forked from Mirrors/wine-wine
oleaut32: Fix RecordCopy()/RecordClear() behavior.
parent
f608c5d2ae
commit
60252ea65b
|
@ -27,6 +27,7 @@
|
|||
#include "objbase.h"
|
||||
#include "oaidl.h"
|
||||
#include "oleauto.h"
|
||||
#include "variant.h"
|
||||
|
||||
#include "wine/unicode.h"
|
||||
#include "wine/debug.h"
|
||||
|
@ -236,6 +237,7 @@ static HRESULT WINAPI IRecordInfoImpl_RecordClear(IRecordInfo *iface, PVOID pvEx
|
|||
case VT_UI8:
|
||||
case VT_INT:
|
||||
case VT_UINT:
|
||||
case VT_HRESULT:
|
||||
break;
|
||||
case VT_INT_PTR:
|
||||
case VT_UINT_PTR:
|
||||
|
@ -244,6 +246,15 @@ static HRESULT WINAPI IRecordInfoImpl_RecordClear(IRecordInfo *iface, PVOID pvEx
|
|||
case VT_SAFEARRAY:
|
||||
SafeArrayDestroy(var);
|
||||
break;
|
||||
case VT_UNKNOWN:
|
||||
case VT_DISPATCH:
|
||||
{
|
||||
IUnknown *unk = *(IUnknown**)var;
|
||||
if (unk)
|
||||
IUnknown_Release(unk);
|
||||
*(void**)var = NULL;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
FIXME("Not supported vt = %d\n", This->fields[i].vt);
|
||||
break;
|
||||
|
@ -257,14 +268,72 @@ static HRESULT WINAPI IRecordInfoImpl_RecordCopy(IRecordInfo *iface, PVOID pvExi
|
|||
PVOID pvNew)
|
||||
{
|
||||
IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
|
||||
HRESULT hr = S_OK;
|
||||
int i;
|
||||
|
||||
TRACE("(%p)->(%p %p)\n", This, pvExisting, pvNew);
|
||||
|
||||
|
||||
if(!pvExisting || !pvNew)
|
||||
return E_INVALIDARG;
|
||||
|
||||
memcpy(pvExisting, pvNew, This->size);
|
||||
return S_OK;
|
||||
/* release already stored data */
|
||||
IRecordInfo_RecordClear(iface, pvNew);
|
||||
|
||||
for (i = 0; i < This->n_vars; i++)
|
||||
{
|
||||
void *src, *dest;
|
||||
|
||||
if (This->fields[i].varkind != VAR_PERINSTANCE) {
|
||||
ERR("varkind != VAR_PERINSTANCE\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
src = ((BYTE*)pvExisting) + This->fields[i].offset;
|
||||
dest = ((BYTE*)pvNew) + This->fields[i].offset;
|
||||
switch (This->fields[i].vt)
|
||||
{
|
||||
case VT_BSTR:
|
||||
{
|
||||
BSTR src_str = *(BSTR*)src;
|
||||
|
||||
if (src_str)
|
||||
{
|
||||
BSTR str = SysAllocString(*(BSTR*)src);
|
||||
if (!str) hr = E_OUTOFMEMORY;
|
||||
|
||||
*(BSTR*)dest = str;
|
||||
}
|
||||
else
|
||||
*(BSTR*)dest = NULL;
|
||||
break;
|
||||
}
|
||||
case VT_UNKNOWN:
|
||||
case VT_DISPATCH:
|
||||
{
|
||||
IUnknown *unk = *(IUnknown**)src;
|
||||
*(IUnknown**)dest = unk;
|
||||
if (unk) IUnknown_AddRef(unk);
|
||||
break;
|
||||
}
|
||||
case VT_SAFEARRAY:
|
||||
hr = SafeArrayCopy(src, dest);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
/* copy directly for types that don't need deep copy */
|
||||
int len = get_type_size(NULL, This->fields[i].vt);
|
||||
memcpy(dest, src, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (FAILED(hr)) break;
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
IRecordInfo_RecordClear(iface, pvNew);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI IRecordInfoImpl_GetGuid(IRecordInfo *iface, GUID *pguid)
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#pragma makedep ident
|
||||
#pragma makedep typelib
|
||||
|
||||
import "oaidl.idl"; /* needed by widl */
|
||||
|
@ -42,6 +43,9 @@ library Test
|
|||
[uuid(4029f190-ca4a-4611-aeb9-673983cb96dd)]
|
||||
struct test_struct
|
||||
{
|
||||
HRESULT f;
|
||||
HRESULT hr;
|
||||
VARIANT_BOOL b;
|
||||
IDispatch *disp;
|
||||
BSTR bstr;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "tmarshal.h"
|
||||
|
||||
#include "test_reg.h"
|
||||
#include "test_tlb.h"
|
||||
|
||||
#define expect_eq(expr, value, type, format) { type _ret = (expr); ok((value) == _ret, #expr " expected " format " got " format "\n", value, _ret); }
|
||||
#define expect_int(expr, value) expect_eq(expr, (int)(value), int, "%d")
|
||||
|
@ -3938,7 +3939,7 @@ static const type_info info[] = {
|
|||
{
|
||||
"test_struct",
|
||||
"{4029f190-ca4a-4611-aeb9-673983cb96dd}",
|
||||
/* kind */ TKIND_RECORD, /*flags*/ 0, /*align*/ 4, /*size*/ 4
|
||||
/* kind */ TKIND_RECORD, /*flags*/ 0, /*align*/ 4, /*size*/ sizeof(struct test_struct)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -25,6 +25,11 @@
|
|||
#include "oleauto.h"
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include "test_tlb.h"
|
||||
|
||||
#include "initguid.h"
|
||||
|
||||
DEFINE_GUID(UUID_test_struct, 0x4029f190, 0xca4a, 0x4611, 0xae,0xb9,0x67,0x39,0x83,0xcb,0x96,0xdd);
|
||||
|
||||
/* Some Visual C++ versions choke on __uint64 to float conversions.
|
||||
* To fix this you need either VC++ 6.0 plus the processor pack
|
||||
|
@ -6265,6 +6270,129 @@ static void test_bstr_cache(void)
|
|||
SysFreeString(str2);
|
||||
}
|
||||
|
||||
static void write_typelib(int res_no, const char *filename)
|
||||
{
|
||||
DWORD written;
|
||||
HANDLE file;
|
||||
HRSRC res;
|
||||
void *ptr;
|
||||
|
||||
file = CreateFileA( filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 );
|
||||
ok( file != INVALID_HANDLE_VALUE, "file creation failed\n" );
|
||||
if (file == INVALID_HANDLE_VALUE) return;
|
||||
res = FindResourceA( GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(res_no), "TYPELIB" );
|
||||
ok( res != 0, "couldn't find resource\n" );
|
||||
ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res ));
|
||||
WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL );
|
||||
ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" );
|
||||
CloseHandle( file );
|
||||
}
|
||||
|
||||
static const char *create_test_typelib(int res_no)
|
||||
{
|
||||
static char filename[MAX_PATH];
|
||||
|
||||
GetTempFileNameA( ".", "tlb", 0, filename );
|
||||
write_typelib(res_no, filename);
|
||||
return filename;
|
||||
}
|
||||
|
||||
static void test_recinfo(void)
|
||||
{
|
||||
static const WCHAR testW[] = {'t','e','s','t',0};
|
||||
static WCHAR teststructW[] = {'t','e','s','t','_','s','t','r','u','c','t',0};
|
||||
struct test_struct teststruct, testcopy;
|
||||
WCHAR filenameW[MAX_PATH];
|
||||
const char *filename;
|
||||
IRecordInfo *recinfo;
|
||||
ITypeInfo *typeinfo;
|
||||
DummyDispatch dispatch;
|
||||
ITypeLib *typelib;
|
||||
TYPEATTR *attr;
|
||||
MEMBERID memid;
|
||||
UINT16 found;
|
||||
HRESULT hr;
|
||||
ULONG size;
|
||||
|
||||
filename = create_test_typelib(2);
|
||||
MultiByteToWideChar(CP_ACP, 0, filename, -1, filenameW, MAX_PATH);
|
||||
hr = LoadTypeLibEx(filenameW, REGKIND_NONE, &typelib);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
|
||||
typeinfo = NULL;
|
||||
found = 1;
|
||||
hr = ITypeLib_FindName(typelib, teststructW, 0, &typeinfo, &memid, &found);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
ok(typeinfo != NULL, "got %p\n", typeinfo);
|
||||
hr = ITypeInfo_GetTypeAttr(typeinfo, &attr);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
ok(IsEqualGUID(&attr->guid, &UUID_test_struct), "got %s\n", wine_dbgstr_guid(&attr->guid));
|
||||
ok(attr->typekind == TKIND_RECORD, "got %d\n", attr->typekind);
|
||||
|
||||
hr = GetRecordInfoFromTypeInfo(typeinfo, &recinfo);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
|
||||
size = 0;
|
||||
hr = IRecordInfo_GetSize(recinfo, &size);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
ok(size == sizeof(struct test_struct), "got size %d\n", size);
|
||||
ok(attr->cbSizeInstance == sizeof(struct test_struct), "got instance size %d\n", attr->cbSizeInstance);
|
||||
ITypeInfo_ReleaseTypeAttr(typeinfo, attr);
|
||||
|
||||
/* RecordInit() */
|
||||
teststruct.hr = E_FAIL;
|
||||
teststruct.b = 0x1;
|
||||
teststruct.disp = (void*)0xdeadbeef;
|
||||
teststruct.bstr = (void*)0xdeadbeef;
|
||||
|
||||
hr = IRecordInfo_RecordInit(recinfo, &teststruct);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
ok(teststruct.hr == 0, "got 0x%08x\n", teststruct.hr);
|
||||
ok(teststruct.b == 0, "got 0x%08x\n", teststruct.b);
|
||||
ok(teststruct.disp == NULL, "got %p\n", teststruct.disp);
|
||||
ok(teststruct.bstr == NULL, "got %p\n", teststruct.bstr);
|
||||
|
||||
init_test_dispatch(10, VT_UI1, &dispatch);
|
||||
|
||||
/* RecordCopy(), interface field reference increased */
|
||||
teststruct.hr = S_FALSE;
|
||||
teststruct.b = VARIANT_TRUE;
|
||||
teststruct.disp = &dispatch.IDispatch_iface;
|
||||
teststruct.bstr = SysAllocString(testW);
|
||||
memset(&testcopy, 0, sizeof(testcopy));
|
||||
hr = IRecordInfo_RecordCopy(recinfo, &teststruct, &testcopy);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
ok(testcopy.hr == S_FALSE, "got 0x%08x\n", testcopy.hr);
|
||||
ok(testcopy.b == VARIANT_TRUE, "got %d\n", testcopy.b);
|
||||
ok(testcopy.disp == teststruct.disp, "got %p\n", testcopy.disp);
|
||||
ok(dispatch.ref == 11, "got %d\n", dispatch.ref);
|
||||
ok(testcopy.bstr != teststruct.bstr, "got %p\n", testcopy.bstr);
|
||||
ok(!lstrcmpW(testcopy.bstr, teststruct.bstr), "got %s, %s\n", wine_dbgstr_w(testcopy.bstr), wine_dbgstr_w(teststruct.bstr));
|
||||
|
||||
/* RecordClear() */
|
||||
hr = IRecordInfo_RecordClear(recinfo, &teststruct);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
ok(teststruct.bstr == NULL, "got %p\n", teststruct.bstr);
|
||||
hr = IRecordInfo_RecordClear(recinfo, &testcopy);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
ok(testcopy.bstr == NULL, "got %p\n", testcopy.bstr);
|
||||
|
||||
/* now destination contains inteface pointer */
|
||||
memset(&testcopy, 0, sizeof(testcopy));
|
||||
testcopy.disp = &dispatch.IDispatch_iface;
|
||||
dispatch.ref = 10;
|
||||
|
||||
hr = IRecordInfo_RecordCopy(recinfo, &teststruct, &testcopy);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
ok(dispatch.ref == 9, "got %d\n", dispatch.ref);
|
||||
|
||||
IRecordInfo_Release(recinfo);
|
||||
|
||||
ITypeInfo_Release(typeinfo);
|
||||
ITypeLib_Release(typelib);
|
||||
DeleteFileA(filename);
|
||||
}
|
||||
|
||||
START_TEST(vartype)
|
||||
{
|
||||
hOleaut32 = GetModuleHandleA("oleaut32.dll");
|
||||
|
@ -6566,4 +6694,6 @@ START_TEST(vartype)
|
|||
|
||||
test_NullByRef();
|
||||
test_ChangeType_keep_dst();
|
||||
|
||||
test_recinfo();
|
||||
}
|
||||
|
|
|
@ -198,7 +198,7 @@ typedef struct
|
|||
DWORD switch_is;
|
||||
} variant_wire_t;
|
||||
|
||||
static unsigned int get_type_size(ULONG *pFlags, VARTYPE vt)
|
||||
unsigned int get_type_size(ULONG *pFlags, VARTYPE vt)
|
||||
{
|
||||
if (vt & VT_ARRAY) return 4;
|
||||
|
||||
|
@ -214,6 +214,7 @@ static unsigned int get_type_size(ULONG *pFlags, VARTYPE vt)
|
|||
return sizeof(SHORT);
|
||||
case VT_I4:
|
||||
case VT_UI4:
|
||||
case VT_HRESULT:
|
||||
return sizeof(LONG);
|
||||
case VT_INT:
|
||||
case VT_UINT:
|
||||
|
|
|
@ -124,7 +124,7 @@ typedef struct tagVARIANT_NUMBER_CHARS
|
|||
WCHAR cCurrencyDigitSeparator;
|
||||
} VARIANT_NUMBER_CHARS;
|
||||
|
||||
|
||||
unsigned int get_type_size(ULONG*, VARTYPE);
|
||||
BOOL VARIANT_GetLocalisedText(LANGID, DWORD, WCHAR *) DECLSPEC_HIDDEN;
|
||||
HRESULT VARIANT_ClearInd(VARIANTARG *) DECLSPEC_HIDDEN;
|
||||
BOOL get_date_format(LCID, DWORD, const SYSTEMTIME *,
|
||||
|
|
Loading…
Reference in New Issue