Commit 60252ea6 authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

oleaut32: Fix RecordCopy()/RecordClear() behavior.

parent f608c5d2
......@@ -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 *,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment