usrmarshal.c 64 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Marshaling Tests
 *
 * Copyright 2004 Robert Shearman
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20
 */

21
#define COBJMACROS
22
#define CONST_VTABLE
23

24 25 26 27 28 29 30 31 32
#include <stdarg.h>

#include "windef.h"
#include "winbase.h"
#include "objbase.h"
#include "propidl.h" /* for LPSAFEARRAY_User* routines */

#include "wine/test.h"

33 34 35 36 37 38
#if (__STDC__ && !defined(_FORCENAMELESSUNION)) || defined(NONAMELESSUNION)
# define V_U2(A)  ((A)->n1.n2)
#else
# define V_U2(A)  (*(A))
#endif

39 40 41 42
static HRESULT (WINAPI *pSafeArrayGetIID)(SAFEARRAY*,GUID*);
static HRESULT (WINAPI *pSafeArrayGetVartype)(SAFEARRAY*,VARTYPE*);
static HRESULT (WINAPI *pVarBstrCmp)(BSTR,BSTR,LCID,ULONG);

43 44 45 46 47
static inline SF_TYPE get_union_type(SAFEARRAY *psa)
{
    VARTYPE vt;
    HRESULT hr;

48
    hr = pSafeArrayGetVartype(psa, &vt);
49
    if (FAILED(hr))
50
    {
51 52
        if(psa->fFeatures & FADF_VARIANT) return SF_VARIANT;

53 54 55 56 57 58 59 60 61
        switch(psa->cbElements)
        {
        case 1: vt = VT_I1; break;
        case 2: vt = VT_I2; break;
        case 4: vt = VT_I4; break;
        case 8: vt = VT_I8; break;
        default: return 0;
        }
    }
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112

    if (psa->fFeatures & FADF_HAVEIID)
        return SF_HAVEIID;

    switch (vt)
    {
    case VT_I1:
    case VT_UI1:      return SF_I1;
    case VT_BOOL:
    case VT_I2:
    case VT_UI2:      return SF_I2;
    case VT_INT:
    case VT_UINT:
    case VT_I4:
    case VT_UI4:
    case VT_R4:       return SF_I4;
    case VT_DATE:
    case VT_CY:
    case VT_R8:
    case VT_I8:
    case VT_UI8:      return SF_I8;
    case VT_INT_PTR:
    case VT_UINT_PTR: return (sizeof(UINT_PTR) == 4 ? SF_I4 : SF_I8);
    case VT_BSTR:     return SF_BSTR;
    case VT_DISPATCH: return SF_DISPATCH;
    case VT_VARIANT:  return SF_VARIANT;
    case VT_UNKNOWN:  return SF_UNKNOWN;
    /* Note: Return a non-zero size to indicate vt is valid. The actual size
     * of a UDT is taken from the result of IRecordInfo_GetSize().
     */
    case VT_RECORD:   return SF_RECORD;
    default:          return SF_ERROR;
    }
}

static ULONG get_cell_count(const SAFEARRAY *psa)
{
    const SAFEARRAYBOUND* psab = psa->rgsabound;
    USHORT cCount = psa->cDims;
    ULONG ulNumCells = 1;

    while (cCount--)
    {
         if (!psab->cElements)
            return 0;
        ulNumCells *= psab->cElements;
        psab++;
    }
    return ulNumCells;
}

113 114 115 116 117 118 119 120
static DWORD elem_wire_size(LPSAFEARRAY lpsa, SF_TYPE sftype)
{
    if (sftype == SF_BSTR)
        return sizeof(DWORD);
    else
        return lpsa->cbElements;
}

121 122 123
static void check_safearray(void *buffer, LPSAFEARRAY lpsa)
{
    unsigned char *wiresa = buffer;
124
    const SAFEARRAYBOUND *bounds;
125 126 127
    VARTYPE vt;
    SF_TYPE sftype;
    ULONG cell_count;
128
    int i;
129 130 131

    if(!lpsa)
    {
132
        ok(*(DWORD *)wiresa == 0, "wiresa + 0x0 should be NULL instead of 0x%08x\n", *(DWORD *)wiresa);
133 134 135
        return;
    }

136 137 138 139
    if (!pSafeArrayGetVartype || !pSafeArrayGetIID)
        return;

    if(FAILED(pSafeArrayGetVartype(lpsa, &vt)))
140 141
        vt = 0;

142 143 144
    sftype = get_union_type(lpsa);
    cell_count = get_cell_count(lpsa);

145
    ok(*(DWORD *)wiresa, "wiresa + 0x0 should be non-NULL instead of 0x%08x\n", *(DWORD *)wiresa); /* win2k: this is lpsa. winxp: this is 0x00000001 */
146
    wiresa += sizeof(DWORD);
147
    ok(*(DWORD *)wiresa == lpsa->cDims, "wiresa + 0x4 should be lpsa->cDims instead of 0x%08x\n", *(DWORD *)wiresa);
148 149 150
    wiresa += sizeof(DWORD);
    ok(*(WORD *)wiresa == lpsa->cDims, "wiresa + 0x8 should be lpsa->cDims instead of 0x%04x\n", *(WORD *)wiresa);
    wiresa += sizeof(WORD);
151
    ok(*(WORD *)wiresa == lpsa->fFeatures, "wiresa + 0xa should be lpsa->fFeatures instead of 0x%08x\n", *(WORD *)wiresa);
152
    wiresa += sizeof(WORD);
153
    ok(*(DWORD *)wiresa == elem_wire_size(lpsa, sftype), "wiresa + 0xc should be 0x%08x instead of 0x%08x\n", elem_wire_size(lpsa, sftype), *(DWORD *)wiresa);
154
    wiresa += sizeof(DWORD);
155
    ok(*(WORD *)wiresa == lpsa->cLocks, "wiresa + 0x10 should be lpsa->cLocks instead of 0x%04x\n", *(WORD *)wiresa);
156
    wiresa += sizeof(WORD);
157
    ok(*(WORD *)wiresa == vt, "wiresa + 0x12 should be %04x instead of 0x%04x\n", vt, *(WORD *)wiresa);
158
    wiresa += sizeof(WORD);
159
    ok(*(DWORD *)wiresa == sftype, "wiresa + 0x14 should be %08x instead of 0x%08x\n", (DWORD)sftype, *(DWORD *)wiresa);
160
    wiresa += sizeof(DWORD);
161
    ok(*(DWORD *)wiresa == cell_count, "wiresa + 0x18 should be %u instead of %u\n", cell_count, *(DWORD *)wiresa);
162
    wiresa += sizeof(DWORD);
163
    ok(*(DWORD *)wiresa, "wiresa + 0x1c should be non-zero instead of 0x%08x\n", *(DWORD *)wiresa);
164
    wiresa += sizeof(DWORD);
165 166 167
    if(sftype == SF_HAVEIID)
    {
        GUID guid;
168
        pSafeArrayGetIID(lpsa, &guid);
169
        ok(IsEqualGUID(&guid, wiresa), "guid mismatch\n");
170 171
        wiresa += sizeof(GUID);
    }
172 173 174 175 176 177 178 179 180 181 182 183

    /* bounds are marshaled in natural dimensions order */
    bounds = (SAFEARRAYBOUND*)wiresa;
    for(i=0; i<lpsa->cDims; i++)
    {
        ok(memcmp(bounds, &lpsa->rgsabound[lpsa->cDims-i-1], sizeof(SAFEARRAYBOUND)) == 0,
           "bounds mismatch for dimension %d, got (%d,%d), expected (%d,%d)\n", i,
            bounds->lLbound, bounds->cElements, lpsa->rgsabound[lpsa->cDims-i-1].lLbound,
            lpsa->rgsabound[lpsa->cDims-i-1].cElements);
        bounds++;
    }

184 185
    wiresa += sizeof(lpsa->rgsabound[0]) * lpsa->cDims;

186
    ok(*(DWORD *)wiresa == cell_count, "wiresa + 0x28 should be %u instead of %u\n", cell_count, *(DWORD*)wiresa);
187 188 189 190
    wiresa += sizeof(DWORD);
    /* elements are now pointed to by wiresa */
}

191 192
static void * WINAPI user_allocate(SIZE_T size)
{
193
    ok(0, "unexpected user_allocate call\n");
194 195 196 197 198
    return CoTaskMemAlloc(size);
}

static void WINAPI user_free(void *p)
{
199
    ok(0, "unexpected user_free call\n");
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
    CoTaskMemFree(p);
}

static void init_user_marshal_cb(USER_MARSHAL_CB *umcb,
                                 PMIDL_STUB_MESSAGE stub_msg,
                                 PRPC_MESSAGE rpc_msg, unsigned char *buffer,
                                 unsigned int size, MSHCTX context)
{
    memset(rpc_msg, 0, sizeof(*rpc_msg));
    rpc_msg->Buffer = buffer;
    rpc_msg->BufferLength = size;

    memset(stub_msg, 0, sizeof(*stub_msg));
    stub_msg->RpcMsg = rpc_msg;
    stub_msg->Buffer = buffer;
    stub_msg->pfnAllocate = user_allocate;
    stub_msg->pfnFree = user_free;

    memset(umcb, 0, sizeof(*umcb));
    umcb->Flags = MAKELONG(context, NDR_LOCAL_DATA_REPRESENTATION);
    umcb->pStubMsg = stub_msg;
    umcb->Signature = USER_MARSHAL_CB_SIGNATURE;
    umcb->CBType = buffer ? USER_MARSHAL_CB_UNMARSHALL : USER_MARSHAL_CB_BUFFER_SIZE;
}

225 226
static void test_marshal_LPSAFEARRAY(void)
{
227
    unsigned char *buffer, *next;
228
    ULONG size, expected;
229 230
    LPSAFEARRAY lpsa;
    LPSAFEARRAY lpsa2 = NULL;
231
    SAFEARRAYBOUND sab[2];
232 233 234
    RPC_MESSAGE rpc_msg;
    MIDL_STUB_MESSAGE stub_msg;
    USER_MARSHAL_CB umcb;
235
    HRESULT hr;
236
    VARTYPE vt, vt2;
237 238 239 240
    OLECHAR *values[10];
    int expected_bstr_size;
    int i;
    LONG indices[1];
241

242 243
    sab[0].lLbound = 5;
    sab[0].cElements = 10;
244

245
    lpsa = SafeArrayCreate(VT_I2, 1, sab);
246 247 248
    *(DWORD *)lpsa->pvData = 0xcafebabe;

    lpsa->cLocks = 7;
249
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
250
    size = LPSAFEARRAY_UserSize(&umcb.Flags, 1, &lpsa);
251
    expected = (44 + 1 + sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1);
252
    expected += sab[0].cElements * sizeof(USHORT);
253 254
    ok(size == expected || size == expected + 12, /* win64 */
       "size should be %u bytes, not %u\n", expected, size);
255
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
256
    size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa);
257 258 259 260 261 262 263
    expected = 44 + sab[0].cElements * sizeof(USHORT);
    ok(size == expected || size == expected + 12, /* win64 */
       "size should be %u bytes, not %u\n", expected, size);
    buffer = HeapAlloc(GetProcessHeap(), 0, size);
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
    next = LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa);
    ok(next - buffer == expected, "Marshaled %u bytes, expected %u\n", (ULONG) (next - buffer), expected);
264
    ok(lpsa->cLocks == 7, "got lock count %u\n", lpsa->cLocks);
265 266 267

    check_safearray(buffer, lpsa);

268 269 270
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
    LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2);
    ok(lpsa2 != NULL, "LPSAFEARRAY didn't unmarshal\n");
271 272 273 274 275 276
    if (pSafeArrayGetVartype)
    {
        pSafeArrayGetVartype(lpsa, &vt);
        pSafeArrayGetVartype(lpsa2, &vt2);
        ok(vt == vt2, "vts differ %x %x\n", vt, vt2);
    }
277 278 279
    ok(lpsa2->cLocks == 0, "got lock count %u, expected 0\n", lpsa2->cLocks);
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
    LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2);
280
    ok(!lpsa2, "lpsa2 was not set to 0 by LPSAFEARRAY_UserFree\n");
281 282
    HeapFree(GetProcessHeap(), 0, buffer);
    lpsa->cLocks = 0;
283 284
    hr = SafeArrayDestroy(lpsa);
    ok(hr == S_OK, "got 0x%08x\n", hr);
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304

    /* use two dimensions */
    sab[0].lLbound = 5;
    sab[0].cElements = 10;
    sab[1].lLbound = 1;
    sab[1].cElements = 2;

    lpsa = SafeArrayCreate(VT_I2, 2, sab);
    *(DWORD *)lpsa->pvData = 0xcafebabe;

    lpsa->cLocks = 7;
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
    size = LPSAFEARRAY_UserSize(&umcb.Flags, 1, &lpsa);
    expected = (44 + 1 + +sizeof(SAFEARRAYBOUND) + sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1);
    expected += max(sab[0].cElements, sab[1].cElements) * lpsa->cDims * sizeof(USHORT);
    ok(size == expected || size == expected + 12, /* win64 */
       "size should be %u bytes, not %u\n", expected, size);
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
    size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa);
    expected = 52 + max(sab[0].cElements, sab[1].cElements) * lpsa->cDims * sizeof(USHORT);
305 306
    ok(size == expected || size == expected + 12, /* win64 */
       "size should be %u bytes, not %u\n", expected, size);
307
    buffer = HeapAlloc(GetProcessHeap(), 0, size);
308
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
309 310
    next = LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa);
    ok(next - buffer == expected, "Marshaled %u bytes, expected %u\n", (ULONG) (next - buffer), expected);
311
    ok(lpsa->cLocks == 7, "got lock count %u\n", lpsa->cLocks);
312 313

    check_safearray(buffer, lpsa);
314

315 316 317
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
    LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2);
    ok(lpsa2 != NULL, "LPSAFEARRAY didn't unmarshal\n");
318 319 320 321 322 323
    if (pSafeArrayGetVartype)
    {
        pSafeArrayGetVartype(lpsa, &vt);
        pSafeArrayGetVartype(lpsa2, &vt2);
        ok(vt == vt2, "vts differ %x %x\n", vt, vt2);
    }
324 325 326
    ok(lpsa2->cLocks == 0, "got lock count %u, expected 0\n", lpsa2->cLocks);
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
    LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2);
327
    HeapFree(GetProcessHeap(), 0, buffer);
328
    lpsa->cLocks = 0;
329 330
    hr = SafeArrayDestroy(lpsa);
    ok(hr == S_OK, "got 0x%08x\n", hr);
331 332 333 334

    /* test NULL safe array */
    lpsa = NULL;

335
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
336
    size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa);
337 338
    expected = 4;
    ok(size == expected, "size should be 4 bytes, not %d\n", size);
339
    buffer = HeapAlloc(GetProcessHeap(), 0, size);
340
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
341 342
    next = LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa);
    ok(next - buffer == expected, "Marshaled %u bytes, expected %u\n", (ULONG) (next - buffer), expected);
343
    check_safearray(buffer, lpsa);
344

345 346 347 348 349
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
    LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2);
    ok(lpsa2 == NULL, "NULL LPSAFEARRAY didn't unmarshal\n");
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
    LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2);
350
    HeapFree(GetProcessHeap(), 0, buffer);
351

352 353
    sab[0].lLbound = 5;
    sab[0].cElements = 10;
354

355
    lpsa = SafeArrayCreate(VT_R8, 1, sab);
356 357 358
    *(double *)lpsa->pvData = 3.1415;

    lpsa->cLocks = 7;
359
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
360
    size = LPSAFEARRAY_UserSize(&umcb.Flags, 1, &lpsa);
361
    expected = (44 + 1 + (sizeof(double) - 1)) & ~(sizeof(double) - 1);
362
    expected += sab[0].cElements * sizeof(double);
363 364
    ok(size == expected || size == expected + 16, /* win64 */
       "size should be %u bytes, not %u\n", expected, size);
365
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
366
    expected = (44 + (sizeof(double) - 1)) & ~(sizeof(double) - 1);
367
    expected += sab[0].cElements * sizeof(double);
368
    size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa);
369 370
    ok(size == expected || size == expected + 8, /* win64 */
       "size should be %u bytes, not %u\n", expected, size);
371
    buffer = HeapAlloc(GetProcessHeap(), 0, size);
372
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
373
    next = LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa);
374 375
    ok(next - buffer == expected || broken(next - buffer + sizeof(DWORD) == expected),
            "Marshaled %u bytes, expected %u\n", (ULONG) (next - buffer), expected);
376 377 378 379

    check_safearray(buffer, lpsa);

    HeapFree(GetProcessHeap(), 0, buffer);
380
    lpsa->cLocks = 0;
381 382
    hr = SafeArrayDestroy(lpsa);
    ok(hr == S_OK, "got 0x%08x\n", hr);
383 384 385 386 387 388 389 390 391 392

    /* VARTYPE-less arrays can be marshaled if cbElements is 1,2,4 or 8 as type SF_In */
    hr = SafeArrayAllocDescriptor(1, &lpsa);
    ok(hr == S_OK, "saad failed %08x\n", hr);
    lpsa->cbElements = 8;
    lpsa->rgsabound[0].lLbound = 2;
    lpsa->rgsabound[0].cElements = 48;
    hr = SafeArrayAllocData(lpsa);
    ok(hr == S_OK, "saad failed %08x\n", hr);

393 394 395 396 397
    if (pSafeArrayGetVartype)
    {
        hr = pSafeArrayGetVartype(lpsa, &vt);
        ok(hr == E_INVALIDARG, "ret %08x\n", hr);
    }
398

399
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
400
    size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa);
401 402 403 404
    expected = (44 + lpsa->cbElements - 1) & ~(lpsa->cbElements - 1);
    expected += lpsa->cbElements * lpsa->rgsabound[0].cElements;
    ok(size == expected || size == expected + 8,  /* win64 */
       "size should be %u bytes, not %u\n", expected, size);
405
    buffer = HeapAlloc(GetProcessHeap(), 0, size);
406
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
407
    next = LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa);
408 409
    ok(next - buffer == expected || broken(next - buffer + sizeof(DWORD) == expected),
            "Marshaled %u bytes, expected %u\n", (ULONG) (next - buffer), expected);
410 411
    check_safearray(buffer, lpsa);
    HeapFree(GetProcessHeap(), 0, buffer);
412 413 414 415
    hr = SafeArrayDestroyData(lpsa);
    ok(hr == S_OK, "got 0x%08x\n", hr);
    hr = SafeArrayDestroyDescriptor(lpsa);
    ok(hr == S_OK, "got 0x%08x\n", hr);
416

417
    /* Test an array of VT_BSTR */
418 419
    sab[0].lLbound = 3;
    sab[0].cElements = sizeof(values) / sizeof(values[0]);
420

421
    lpsa = SafeArrayCreate(VT_BSTR, 1, sab);
422
    expected_bstr_size = 0;
423
    for (i = 0; i < sab[0].cElements; i++)
424 425 426 427 428 429
    {
        int j;
        WCHAR buf[128];
        for (j = 0; j <= i; j++)
            buf[j] = 'a' + j;
        buf[j] = 0;
430
        indices[0] = i + sab[0].lLbound;
431 432 433 434 435 436 437 438 439 440
        values[i] = SysAllocString(buf);
        hr = SafeArrayPutElement(lpsa, indices, values[i]);
        ok(hr == S_OK, "Failed to put bstr element hr 0x%x\n", hr);
        expected_bstr_size += (j * sizeof(WCHAR)) + (3 * sizeof(DWORD));
        if (i % 2 == 0) /* Account for DWORD padding.  Works so long as cElements is even */
            expected_bstr_size += sizeof(WCHAR);
    }

    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
    size = LPSAFEARRAY_UserSize(&umcb.Flags, 1, &lpsa);
441
    expected = 44 + (sab[0].cElements * sizeof(DWORD)) + expected_bstr_size;
442
    todo_wine
443 444
    ok(size == expected + sizeof(DWORD) || size  == (expected + sizeof(DWORD) + 12 /* win64 */),
            "size should be %u bytes, not %u\n", expected + (ULONG) sizeof(DWORD), size);
445 446 447
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
    size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa);
    todo_wine
448 449
    ok(size == expected || size  == (expected + 12 /* win64 */),
        "size should be %u bytes, not %u\n", expected, size);
450 451 452
    buffer = HeapAlloc(GetProcessHeap(), 0, size);
    memset(buffer, 0xcc, size);
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
453 454 455
    next = LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa);
    todo_wine
    ok(next - buffer == expected, "Marshaled %u bytes, expected %u\n", (ULONG) (next - buffer), expected);
456 457 458 459

    check_safearray(buffer, lpsa);

    lpsa2 = NULL;
460 461 462 463 464
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
    next = LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2);
    todo_wine
    ok(next - buffer == expected, "Marshaled %u bytes, expected %u\n", (ULONG) (next - buffer), expected);
    ok(lpsa2 != NULL, "LPSAFEARRAY didn't unmarshal, result %p\n", next);
465 466 467 468 469 470 471

    for (i = 0; i < sizeof(values) / sizeof(values[0]); i++)
    {
        BSTR gotvalue = NULL;

        if (lpsa2)
        {
472
            indices[0] = i + sab[0].lLbound;
473 474 475
            hr = SafeArrayGetElement(lpsa2, indices, &gotvalue);
            ok(hr == S_OK, "Failed to get bstr element at hres 0x%x\n", hr);
            if (hr == S_OK)
476
            {
477 478
                if (pVarBstrCmp)
                    ok(pVarBstrCmp(values[i], gotvalue, 0, 0) == VARCMP_EQ, "String %d does not match\n", i);
479 480
                SysFreeString(gotvalue);
            }
481 482 483 484 485
        }

        SysFreeString(values[i]);
    }

486 487
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
    LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2);
488 489

    HeapFree(GetProcessHeap(), 0, buffer);
490 491
    hr = SafeArrayDestroy(lpsa);
    ok(hr == S_OK, "got 0x%08x\n", hr);
492

493 494 495
    /* VARTYPE-less arrays with FADF_VARIANT */
    hr = SafeArrayAllocDescriptor(1, &lpsa);
    ok(hr == S_OK, "saad failed %08x\n", hr);
496
    lpsa->cbElements = sizeof(VARIANT);
497 498 499 500 501 502
    lpsa->fFeatures = FADF_VARIANT;
    lpsa->rgsabound[0].lLbound = 2;
    lpsa->rgsabound[0].cElements = 48;
    hr = SafeArrayAllocData(lpsa);
    ok(hr == S_OK, "saad failed %08x\n", hr);

503 504 505 506 507
    if (pSafeArrayGetVartype)
    {
        hr = pSafeArrayGetVartype(lpsa, &vt);
        ok(hr == E_INVALIDARG, "ret %08x\n", hr);
    }
508

509
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
510
    size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa);
511
    expected = 44 + 28 * lpsa->rgsabound[0].cElements;
512
    todo_wine
513 514
    ok(size == expected || size == expected + 8,  /* win64 */
       "size should be %u bytes, not %u\n", expected, size);
515
    buffer = HeapAlloc(GetProcessHeap(), 0, size);
516
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
517 518
    next = LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa);
    todo_wine
519 520
    ok(next - buffer == expected || broken(next - buffer + sizeof(DWORD) == expected),
            "Marshaled %u bytes, expected %u\n", (ULONG) (next - buffer), expected);
521
    lpsa->cbElements = 16;  /* VARIANT wire size */
522 523
    check_safearray(buffer, lpsa);
    HeapFree(GetProcessHeap(), 0, buffer);
524 525 526 527
    hr = SafeArrayDestroyData(lpsa);
    ok(hr == S_OK, "got 0x%08x\n", hr);
    hr = SafeArrayDestroyDescriptor(lpsa);
    ok(hr == S_OK, "got 0x%08x\n", hr);
528 529
}

530 531 532
static void check_bstr(void *buffer, BSTR b)
{
    DWORD *wireb = buffer;
533
    DWORD len = SysStringByteLen(b);
534

535
    ok(*wireb == (len + 1) / 2, "wv[0] %08x\n", *wireb);
536
    wireb++;
537
    if(b)
538
        ok(*wireb == len, "wv[1] %08x\n", *wireb);
539
    else
540
        ok(*wireb == 0xffffffff, "wv[1] %08x\n", *wireb);
541
    wireb++;
542
    ok(*wireb == (len + 1) / 2, "wv[2] %08x\n", *wireb);
543 544 545
    if(len)
    {
        wireb++;
546
        ok(!memcmp(wireb, b, (len + 1) & ~1), "strings differ\n");
547 548 549 550
    }
    return;
}

551 552
static void test_marshal_BSTR(void)
{
553 554 555 556
    ULONG size;
    RPC_MESSAGE rpc_msg;
    MIDL_STUB_MESSAGE stub_msg;
    USER_MARSHAL_CB umcb;
557
    unsigned char *buffer, *next;
558 559
    BSTR b, b2;
    WCHAR str[] = {'m','a','r','s','h','a','l',' ','t','e','s','t','1',0};
560
    DWORD len;
561 562 563

    b = SysAllocString(str);
    len = SysStringLen(b);
564
    ok(len == 13, "get %d\n", len);
565 566

    /* BSTRs are DWORD aligned */
567 568

    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
569
    size = BSTR_UserSize(&umcb.Flags, 1, &b);
570
    ok(size == 42, "size %d\n", size);
571

572
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
573
    size = BSTR_UserSize(&umcb.Flags, 0, &b);
574
    ok(size == 38, "size %d\n", size);
575 576

    buffer = HeapAlloc(GetProcessHeap(), 0, size);
577
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
578 579
    next = BSTR_UserMarshal(&umcb.Flags, buffer, &b);
    ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
580
    check_bstr(buffer, b);
581

582 583 584 585 586 587 588 589
    b2 = NULL;
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
    next = BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2);
    ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
    ok(b2 != NULL, "BSTR didn't unmarshal\n");
    ok(!memcmp(b, b2, (len + 1) * 2), "strings differ\n");
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
    BSTR_UserFree(&umcb.Flags, &b2);
590 591 592 593 594

    HeapFree(GetProcessHeap(), 0, buffer);
    SysFreeString(b);

    b = NULL;
595
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
596
    size = BSTR_UserSize(&umcb.Flags, 0, &b);
597
    ok(size == 12, "size %d\n", size);
598 599

    buffer = HeapAlloc(GetProcessHeap(), 0, size);
600
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
601 602
    next = BSTR_UserMarshal(&umcb.Flags, buffer, &b);
    ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
603

604
    check_bstr(buffer, b);
605 606 607 608 609 610 611
    b2 = NULL;
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
    next = BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2);
    ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
    ok(b2 == NULL, "NULL BSTR didn't unmarshal\n");
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
    BSTR_UserFree(&umcb.Flags, &b2);
612 613
    HeapFree(GetProcessHeap(), 0, buffer);

614 615 616
    b = SysAllocStringByteLen("abc", 3);
    *(((char*)b) + 3) = 'd';
    len = SysStringLen(b);
617
    ok(len == 1, "get %d\n", len);
618
    len = SysStringByteLen(b);
619
    ok(len == 3, "get %d\n", len);
620

621
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
622
    size = BSTR_UserSize(&umcb.Flags, 0, &b);
623
    ok(size == 16, "size %d\n", size);
624 625 626

    buffer = HeapAlloc(GetProcessHeap(), 0, size);
    memset(buffer, 0xcc, size);
627
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
628 629 630 631 632
    next = BSTR_UserMarshal(&umcb.Flags, buffer, &b);
    ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
    check_bstr(buffer, b);
    ok(buffer[15] == 'd', "buffer[15] %02x\n", buffer[15]);

633 634 635 636 637 638 639 640
    b2 = NULL;
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
    next = BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2);
    ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
    ok(b2 != NULL, "BSTR didn't unmarshal\n");
    ok(!memcmp(b, b2, len), "strings differ\n");
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
    BSTR_UserFree(&umcb.Flags, &b2);
641 642 643 644 645
    HeapFree(GetProcessHeap(), 0, buffer);
    SysFreeString(b);

    b = SysAllocStringByteLen("", 0);
    len = SysStringLen(b);
646
    ok(len == 0, "get %d\n", len);
647
    len = SysStringByteLen(b);
648
    ok(len == 0, "get %d\n", len);
649

650
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
651
    size = BSTR_UserSize(&umcb.Flags, 0, &b);
652
    ok(size == 12, "size %d\n", size);
653 654

    buffer = HeapAlloc(GetProcessHeap(), 0, size);
655
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
656 657 658 659
    next = BSTR_UserMarshal(&umcb.Flags, buffer, &b);
    ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
    check_bstr(buffer, b);

660 661 662 663 664 665 666 667 668
    b2 = NULL;
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
    next = BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2);
    ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
    ok(b2 != NULL, "NULL LPSAFEARRAY didn't unmarshal\n");
    len = SysStringByteLen(b2);
    ok(len == 0, "byte len %d\n", len);
    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
    BSTR_UserFree(&umcb.Flags, &b2);
669 670
    HeapFree(GetProcessHeap(), 0, buffer);
    SysFreeString(b);
671 672
}

673 674
typedef struct
{
675
    IUnknown IUnknown_iface;
676 677 678
    ULONG refs;
} HeapUnknown;

679 680 681 682 683
static inline HeapUnknown *impl_from_IUnknown(IUnknown *iface)
{
    return CONTAINING_RECORD(iface, HeapUnknown, IUnknown_iface);
}

684 685 686 687 688
static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
{
    if (IsEqualIID(riid, &IID_IUnknown))
    {
        IUnknown_AddRef(iface);
689
        *ppv = iface;
690 691 692 693 694 695 696 697
        return S_OK;
    }
    *ppv = NULL;
    return E_NOINTERFACE;
}

static ULONG WINAPI HeapUnknown_AddRef(IUnknown *iface)
{
698
    HeapUnknown *This = impl_from_IUnknown(iface);
699 700 701 702 703
    return InterlockedIncrement((LONG*)&This->refs);
}

static ULONG WINAPI HeapUnknown_Release(IUnknown *iface)
{
704
    HeapUnknown *This = impl_from_IUnknown(iface);
705 706 707 708 709 710 711 712 713 714 715 716
    ULONG refs = InterlockedDecrement((LONG*)&This->refs);
    if (!refs) HeapFree(GetProcessHeap(), 0, This);
    return refs;
}

static const IUnknownVtbl HeapUnknown_Vtbl =
{
    HeapUnknown_QueryInterface,
    HeapUnknown_AddRef,
    HeapUnknown_Release
};

717
typedef struct
718
{
719 720 721 722 723 724
    DWORD clSize;
    DWORD rpcReserved;
    USHORT vt;
    USHORT wReserved1;
    USHORT wReserved2;
    USHORT wReserved3;
725
    DWORD switch_is;
726 727 728 729 730 731 732 733 734 735 736 737 738
} variant_wire_t;

static DWORD *check_variant_header(DWORD *wirev, VARIANT *v, ULONG size)
{
    const variant_wire_t *header = (const variant_wire_t*)wirev;
    DWORD switch_is;

    ok(header->clSize == (size + 7) >> 3, "wv[0] %08x, expected %08x\n", header->clSize, (size + 7) >> 3);
    ok(header->rpcReserved == 0, "wv[1] %08x\n", header->rpcReserved);
    ok(header->vt == V_VT(v), "vt %04x expected %04x\n", header->vt, V_VT(v));
    ok(header->wReserved1 == V_U2(v).wReserved1, "res1 %04x expected %04x\n", header->wReserved1, V_U2(v).wReserved1);
    ok(header->wReserved2 == V_U2(v).wReserved2, "res2 %04x expected %04x\n", header->wReserved2, V_U2(v).wReserved2);
    ok(header->wReserved3 == V_U2(v).wReserved3, "res3 %04x expected %04x\n", header->wReserved3, V_U2(v).wReserved3);
739 740 741 742

    switch_is = V_VT(v);
    if(switch_is & VT_ARRAY)
        switch_is &= ~VT_TYPEMASK;
743 744 745
    ok(header->switch_is == switch_is, "switch_is %08x expected %08x\n", header->switch_is, switch_is);

    return (DWORD*)((unsigned char*)wirev + sizeof(variant_wire_t));
746 747
}

748 749 750 751 752 753 754 755 756
/* Win9x and WinME don't always align as needed. Variants have
 * an alignment of 8.
 */
static void *alloc_aligned(SIZE_T size, void **buf)
{
    *buf = HeapAlloc(GetProcessHeap(), 0, size + 7);
    return (void *)(((UINT_PTR)*buf + 7) & ~7);
}

757 758
static void test_marshal_VARIANT(void)
{
759
    VARIANT v, v2, v3;
760
    MIDL_STUB_MESSAGE stubMsg = { 0 };
761
    RPC_MESSAGE rpcMsg = { 0 };
762 763
    USER_MARSHAL_CB umcb = { 0 };
    unsigned char *buffer, *next;
764
    void *oldbuffer;
765
    ULONG ul;
766 767
    short s;
    double d;
768
    void *mem;
769
    DWORD *wirev;
770
    BSTR b, b2;
771 772
    WCHAR str[] = {'m','a','r','s','h','a','l',' ','t','e','s','t',0};
    SAFEARRAYBOUND sab;
773
    LPSAFEARRAY lpsa, lpsa2, lpsa_copy;
774
    DECIMAL dec, dec2;
775
    HeapUnknown *heap_unknown;
776
    DWORD expected;
777
    HRESULT hr;
778 779
    LONG bound, bound2;
    VARTYPE vt, vt2;
780

781 782
    stubMsg.RpcMsg = &rpcMsg;

783 784
    umcb.Flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
    umcb.pStubMsg = &stubMsg;
785 786 787
    umcb.pReserve = NULL;
    umcb.Signature = USER_MARSHAL_CB_SIGNATURE;
    umcb.CBType = USER_MARSHAL_CB_UNMARSHALL;
788 789 790 791 792 793

    /*** I1 ***/
    VariantInit(&v);
    V_VT(&v) = VT_I1;
    V_I1(&v) = 0x12;

794 795 796 797 798 799 800
    /* check_variant_header tests wReserved[123], so initialize to unique values.
     * (Could probably also do this by setting the variant to a known DECIMAL.)
     */
    V_U2(&v).wReserved1 = 0x1234;
    V_U2(&v).wReserved2 = 0x5678;
    V_U2(&v).wReserved3 = 0x9abc;

801
    /* Variants have an alignment of 8 */
802 803
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 1, &v);
    ok(stubMsg.BufferLength == 29, "size %d\n", stubMsg.BufferLength);
804

805 806
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength == 21, "size %d\n", stubMsg.BufferLength);
807

808
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
809
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
810
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
811
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
812 813
    wirev = (DWORD*)buffer;
    
814
    wirev = check_variant_header(wirev, &v, stubMsg.BufferLength);
815
    ok(*(char*)wirev == V_I1(&v), "wv[5] %08x\n", *wirev);
816 817 818 819 820 821 822 823
    VariantInit(&v2);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
    ok(V_I1(&v) == V_I1(&v2), "got i1 %x expect %x\n", V_I1(&v), V_I1(&v2));

    VARIANT_UserFree(&umcb.Flags, &v2);
824
    HeapFree(GetProcessHeap(), 0, oldbuffer);
825 826 827 828 829 830

    /*** I2 ***/
    VariantInit(&v);
    V_VT(&v) = VT_I2;
    V_I2(&v) = 0x1234;

831 832
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength == 22, "size %d\n", stubMsg.BufferLength);
833

834
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
835
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
836
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
837
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
838 839
    wirev = (DWORD*)buffer;

840
    wirev = check_variant_header(wirev, &v, stubMsg.BufferLength);
841
    ok(*(short*)wirev == V_I2(&v), "wv[5] %08x\n", *wirev);
842 843 844 845 846 847 848 849
    VariantInit(&v2);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
    ok(V_I2(&v) == V_I2(&v2), "got i2 %x expect %x\n", V_I2(&v), V_I2(&v2));

    VARIANT_UserFree(&umcb.Flags, &v2);
850
    HeapFree(GetProcessHeap(), 0, oldbuffer);
851 852 853 854 855 856 857

    /*** I2 BYREF ***/
    VariantInit(&v);
    V_VT(&v) = VT_I2 | VT_BYREF;
    s = 0x1234;
    V_I2REF(&v) = &s;

858 859
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength == 26, "size %d\n", stubMsg.BufferLength);
860

861
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
862
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
863
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
864
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
865 866
    wirev = (DWORD*)buffer;

867
    wirev = check_variant_header(wirev, &v, stubMsg.BufferLength);
868
    ok(*wirev == 0x4, "wv[5] %08x\n", *wirev);
869
    wirev++;
870
    ok(*(short*)wirev == s, "wv[6] %08x\n", *wirev);
871 872 873 874 875 876 877 878 879 880 881
    VariantInit(&v2);
    V_VT(&v2) = VT_I2 | VT_BYREF;
    V_BYREF(&v2) = mem = CoTaskMemAlloc(sizeof(V_I2(&v2)));
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
    ok(V_BYREF(&v2) == mem, "didn't reuse existing memory\n");
    ok(*V_I2REF(&v) == *V_I2REF(&v2), "got i2 ref %x expect ui4 ref %x\n", *V_I2REF(&v), *V_I2REF(&v2));

    VARIANT_UserFree(&umcb.Flags, &v2);
882
    HeapFree(GetProcessHeap(), 0, oldbuffer);
883 884 885 886 887 888

    /*** I4 ***/
    VariantInit(&v);
    V_VT(&v) = VT_I4;
    V_I4(&v) = 0x1234;

889 890
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength == 24, "size %d\n", stubMsg.BufferLength);
891

892
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
893
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
894
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
895
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
896 897
    wirev = (DWORD*)buffer;
    
898
    wirev = check_variant_header(wirev, &v, stubMsg.BufferLength);
899
    ok(*wirev == V_I4(&v), "wv[5] %08x\n", *wirev);
900

901 902 903 904 905 906 907 908
    VariantInit(&v2);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
    ok(V_I4(&v) == V_I4(&v2), "got i4 %x expect %x\n", V_I4(&v), V_I4(&v2));

    VARIANT_UserFree(&umcb.Flags, &v2);
909
    HeapFree(GetProcessHeap(), 0, oldbuffer);
910 911 912 913 914 915

    /*** UI4 ***/
    VariantInit(&v);
    V_VT(&v) = VT_UI4;
    V_UI4(&v) = 0x1234;

916 917
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength == 24, "size %d\n", stubMsg.BufferLength);
918

919
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
920
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
921
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
922
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
923 924
    wirev = (DWORD*)buffer;
    
925
    wirev = check_variant_header(wirev, &v, stubMsg.BufferLength);
926
    ok(*wirev == 0x1234, "wv[5] %08x\n", *wirev);
927 928 929 930 931 932 933 934
    VariantInit(&v2);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
    ok(V_UI4(&v) == V_UI4(&v2), "got ui4 %x expect %x\n", V_UI4(&v), V_UI4(&v2));

    VARIANT_UserFree(&umcb.Flags, &v2);
935
    HeapFree(GetProcessHeap(), 0, oldbuffer);
936 937 938 939 940 941 942

    /*** UI4 BYREF ***/
    VariantInit(&v);
    V_VT(&v) = VT_UI4 | VT_BYREF;
    ul = 0x1234;
    V_UI4REF(&v) = &ul;

943 944
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength == 28, "size %d\n", stubMsg.BufferLength);
945

946
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
947
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
948
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
949
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
950 951
    wirev = (DWORD*)buffer;
    
952
    wirev = check_variant_header(wirev, &v, stubMsg.BufferLength);
953
    ok(*wirev == 0x4, "wv[5] %08x\n", *wirev);
954
    wirev++;
955
    ok(*wirev == ul, "wv[6] %08x\n", *wirev);
956

957 958 959 960 961 962 963 964
    VariantInit(&v2);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
    ok(*V_UI4REF(&v) == *V_UI4REF(&v2), "got ui4 ref %x expect ui4 ref %x\n", *V_UI4REF(&v), *V_UI4REF(&v2));

    VARIANT_UserFree(&umcb.Flags, &v2);
965
    HeapFree(GetProcessHeap(), 0, oldbuffer);
966 967 968 969 970 971

    /*** R4 ***/
    VariantInit(&v);
    V_VT(&v) = VT_R4;
    V_R8(&v) = 3.1415;

972 973
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength == 24, "size %d\n", stubMsg.BufferLength);
974

975
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
976
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
977
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
978
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
979 980
    wirev = (DWORD*)buffer;
     
981
    wirev = check_variant_header(wirev, &v, stubMsg.BufferLength);
982
    ok(*(float*)wirev == V_R4(&v), "wv[5] %08x\n", *wirev);
983 984 985 986 987 988 989 990
    VariantInit(&v2);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
    ok(V_R4(&v) == V_R4(&v2), "got r4 %f expect %f\n", V_R4(&v), V_R4(&v2));

    VARIANT_UserFree(&umcb.Flags, &v2);
991
    HeapFree(GetProcessHeap(), 0, oldbuffer);
992 993 994 995 996 997

    /*** R8 ***/
    VariantInit(&v);
    V_VT(&v) = VT_R8;
    V_R8(&v) = 3.1415;

998 999
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength == 32, "size %d\n", stubMsg.BufferLength);
1000

1001
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
1002 1003
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
    memset(buffer, 0xcc, stubMsg.BufferLength);
1004
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
1005
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
1006 1007
    wirev = (DWORD*)buffer;
    
1008
    wirev = check_variant_header(wirev, &v, stubMsg.BufferLength);
1009
    ok(*wirev == 0xcccccccc, "wv[5] %08x\n", *wirev); /* pad */
1010
    wirev++;
1011
    ok(*(double*)wirev == V_R8(&v), "wv[6] %08x, wv[7] %08x\n", *wirev, *(wirev+1));
1012 1013 1014 1015 1016 1017 1018 1019
    VariantInit(&v2);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
    ok(V_R8(&v) == V_R8(&v2), "got r8 %f expect %f\n", V_R8(&v), V_R8(&v2));

    VARIANT_UserFree(&umcb.Flags, &v2);
1020
    HeapFree(GetProcessHeap(), 0, oldbuffer);
1021 1022 1023 1024 1025 1026 1027

    /*** R8 BYREF ***/
    VariantInit(&v);
    V_VT(&v) = VT_R8 | VT_BYREF;
    d = 3.1415;
    V_R8REF(&v) = &d;

1028 1029
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength == 32, "size %d\n", stubMsg.BufferLength);
1030

1031
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
1032
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
1033
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
1034
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
1035 1036
    wirev = (DWORD*)buffer;
    
1037
    wirev = check_variant_header(wirev, &v, stubMsg.BufferLength);
1038
    ok(*wirev == 8, "wv[5] %08x\n", *wirev);
1039
    wirev++;
1040
    ok(*(double*)wirev == d, "wv[6] %08x wv[7] %08x\n", *wirev, *(wirev+1));
1041 1042 1043 1044 1045 1046 1047 1048
    VariantInit(&v2);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
    ok(*V_R8REF(&v) == *V_R8REF(&v2), "got r8 ref %f expect %f\n", *V_R8REF(&v), *V_R8REF(&v2));

    VARIANT_UserFree(&umcb.Flags, &v2);
1049
    HeapFree(GetProcessHeap(), 0, oldbuffer);
1050 1051 1052 1053 1054 1055

    /*** VARIANT_BOOL ***/
    VariantInit(&v);
    V_VT(&v) = VT_BOOL;
    V_BOOL(&v) = 0x1234;

1056 1057
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength == 22, "size %d\n", stubMsg.BufferLength);
1058

1059
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
1060
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
1061
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
1062
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
1063 1064
    wirev = (DWORD*)buffer;
    
1065
    wirev = check_variant_header(wirev, &v, stubMsg.BufferLength);
1066
    ok(*(short*)wirev == V_BOOL(&v), "wv[5] %04x\n", *(WORD*)wirev);
1067 1068 1069 1070 1071 1072 1073 1074
    VariantInit(&v2);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
    ok(V_BOOL(&v) == V_BOOL(&v2), "got bool %x expect %x\n", V_BOOL(&v), V_BOOL(&v2));

    VARIANT_UserFree(&umcb.Flags, &v2);
1075
    HeapFree(GetProcessHeap(), 0, oldbuffer);
1076 1077 1078

    /*** DECIMAL ***/
    VarDecFromI4(0x12345678, &dec);
1079
    dec.wReserved = 0xfedc;          /* Also initialize reserved field, as we check it later */
1080 1081 1082 1083
    VariantInit(&v);
    V_DECIMAL(&v) = dec;
    V_VT(&v) = VT_DECIMAL;

1084 1085
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength == 40, "size %d\n", stubMsg.BufferLength);
1086

1087
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
1088 1089
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
    memset(buffer, 0xcc, stubMsg.BufferLength);
1090
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
1091
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
1092 1093
    wirev = (DWORD*)buffer;

1094
    wirev = check_variant_header(wirev, &v, stubMsg.BufferLength);
1095
    ok(*wirev == 0xcccccccc, "wirev[5] %08x\n", *wirev); /* pad */
1096 1097 1098
    wirev++;
    dec2 = dec;
    dec2.wReserved = VT_DECIMAL;
1099
    ok(!memcmp(wirev, &dec2, sizeof(dec2)), "wirev[6] %08x wirev[7] %08x wirev[8] %08x wirev[9] %08x\n",
1100
       *wirev, *(wirev + 1), *(wirev + 2), *(wirev + 3));
1101 1102 1103 1104 1105 1106 1107 1108
    VariantInit(&v2);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
    ok(!memcmp(&V_DECIMAL(&v), & V_DECIMAL(&v2), sizeof(DECIMAL)), "decimals differ\n");

    VARIANT_UserFree(&umcb.Flags, &v2);
1109
    HeapFree(GetProcessHeap(), 0, oldbuffer);
1110 1111 1112 1113 1114 1115

    /*** DECIMAL BYREF ***/
    VariantInit(&v);
    V_VT(&v) = VT_DECIMAL | VT_BYREF;
    V_DECIMALREF(&v) = &dec;

1116 1117
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength == 40, "size %d\n", stubMsg.BufferLength);
1118

1119
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
1120
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
1121
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
1122
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
1123 1124
    wirev = (DWORD*)buffer;
    
1125
    wirev = check_variant_header(wirev, &v, stubMsg.BufferLength);
1126
    ok(*wirev == 16, "wv[5] %08x\n", *wirev);
1127
    wirev++;
1128
    ok(!memcmp(wirev, &dec, sizeof(dec)), "wirev[6] %08x wirev[7] %08x wirev[8] %08x wirev[9] %08x\n", *wirev, *(wirev + 1), *(wirev + 2), *(wirev + 3));
1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
    VariantInit(&v2);
    /* check_variant_header tests wReserved[123], so initialize to unique values.
     * (Could probably also do this by setting the variant to a known DECIMAL.)
     */
    V_U2(&v2).wReserved1 = 0x0123;
    V_U2(&v2).wReserved2 = 0x4567;
    V_U2(&v2).wReserved3 = 0x89ab;

    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
    ok(!memcmp(V_DECIMALREF(&v), V_DECIMALREF(&v2), sizeof(DECIMAL)), "decimals differ\n");

    VARIANT_UserFree(&umcb.Flags, &v2);
1144
    HeapFree(GetProcessHeap(), 0, oldbuffer);
1145 1146 1147 1148 1149

    /*** EMPTY ***/
    VariantInit(&v);
    V_VT(&v) = VT_EMPTY;

1150 1151
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength == 20, "size %d\n", stubMsg.BufferLength);
1152

1153
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
1154
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
1155
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
1156
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
1157 1158
    wirev = (DWORD*)buffer;

1159
    check_variant_header(wirev, &v, stubMsg.BufferLength);
1160 1161 1162 1163 1164
    VariantInit(&v2);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
1165

1166
    VARIANT_UserFree(&umcb.Flags, &v2);
1167
    HeapFree(GetProcessHeap(), 0, oldbuffer);
1168 1169 1170 1171 1172

    /*** NULL ***/
    VariantInit(&v);
    V_VT(&v) = VT_NULL;

1173 1174
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength == 20, "size %d\n", stubMsg.BufferLength);
1175

1176
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
1177
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
1178
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
1179
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
1180 1181
    wirev = (DWORD*)buffer;

1182
    check_variant_header(wirev, &v, stubMsg.BufferLength);
1183 1184 1185 1186 1187
    VariantInit(&v2);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
1188

1189
    VARIANT_UserFree(&umcb.Flags, &v2);
1190
    HeapFree(GetProcessHeap(), 0, oldbuffer);
1191 1192 1193 1194 1195 1196 1197

    /*** BSTR ***/
    b = SysAllocString(str);
    VariantInit(&v);
    V_VT(&v) = VT_BSTR;
    V_BSTR(&v) = b;

1198 1199
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength == 60, "size %d\n", stubMsg.BufferLength);
1200
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
1201
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
1202
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
1203
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
1204 1205
    wirev = (DWORD*)buffer;
    
1206
    wirev = check_variant_header(wirev, &v, stubMsg.BufferLength);
1207
    ok(*wirev, "wv[5] %08x\n", *wirev); /* win2k: this is b. winxp: this is (char*)b + 1 */
1208 1209
    wirev++;
    check_bstr(wirev, V_BSTR(&v));
1210 1211 1212 1213 1214 1215 1216 1217 1218
    VariantInit(&v2);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
    ok(SysStringByteLen(V_BSTR(&v)) == SysStringByteLen(V_BSTR(&v2)), "bstr string lens differ\n");
    ok(!memcmp(V_BSTR(&v), V_BSTR(&v2), SysStringByteLen(V_BSTR(&v))), "bstrs differ\n");

    VARIANT_UserFree(&umcb.Flags, &v2);
1219
    HeapFree(GetProcessHeap(), 0, oldbuffer);
1220 1221 1222 1223 1224 1225

    /*** BSTR BYREF ***/
    VariantInit(&v);
    V_VT(&v) = VT_BSTR | VT_BYREF;
    V_BSTRREF(&v) = &b;

1226 1227
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength == 64, "size %d\n", stubMsg.BufferLength);
1228
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
1229
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
1230
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
1231
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
1232 1233
    wirev = (DWORD*)buffer;
    
1234
    wirev = check_variant_header(wirev, &v, stubMsg.BufferLength);
1235
    ok(*wirev == 0x4, "wv[5] %08x\n", *wirev);
1236
    wirev++;
1237
    ok(*wirev, "wv[6] %08x\n", *wirev); /* win2k: this is b. winxp: this is (char*)b + 1 */
1238 1239
    wirev++;
    check_bstr(wirev, b);
1240 1241 1242 1243 1244
    b2 = SysAllocString(str);
    b2[0] = 0;
    V_VT(&v2) = VT_BSTR | VT_BYREF;
    V_BSTRREF(&v2) = &b2;
    mem = b2;
1245 1246 1247 1248
    VariantInit(&v2);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
1249
    ok(mem == b2, "BSTR should be reused\n");
1250 1251 1252 1253
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
    ok(SysStringByteLen(*V_BSTRREF(&v)) == SysStringByteLen(*V_BSTRREF(&v2)), "bstr string lens differ\n");
    ok(!memcmp(*V_BSTRREF(&v), *V_BSTRREF(&v2), SysStringByteLen(*V_BSTRREF(&v))), "bstrs differ\n");

1254
    SysFreeString(b2);
1255
    HeapFree(GetProcessHeap(), 0, oldbuffer);
1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269
    SysFreeString(b);

    /*** ARRAY ***/
    sab.lLbound = 5;
    sab.cElements = 10;

    lpsa = SafeArrayCreate(VT_R8, 1, &sab);
    *(DWORD *)lpsa->pvData = 0xcafebabe;
    *((DWORD *)lpsa->pvData + 1) = 0xdeadbeef;

    VariantInit(&v);
    V_VT(&v) = VT_UI4 | VT_ARRAY;
    V_ARRAY(&v) = lpsa;

1270
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
1271 1272 1273
    expected = 152;
    ok(stubMsg.BufferLength == expected || stubMsg.BufferLength == expected + 8, /* win64 */
       "size %u instead of %u\n", stubMsg.BufferLength, expected);
1274
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
1275
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
1276
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
1277
    ok(next == buffer + expected, "got %p expect %p\n", next, buffer + expected);
1278 1279
    wirev = (DWORD*)buffer;
    
1280
    wirev = check_variant_header(wirev, &v, expected);
1281
    ok(*wirev, "wv[5] %08x\n", *wirev); /* win2k: this is lpsa. winxp: this is (char*)lpsa + 1 */
1282 1283
    wirev++;
    check_safearray(wirev, lpsa);
1284 1285 1286 1287 1288
    VariantInit(&v2);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + expected, "got %p expect %p\n", next, buffer + expected);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
1289
    ok(SafeArrayGetDim(V_ARRAY(&v)) == SafeArrayGetDim(V_ARRAY(&v2)), "array dims differ\n");
1290 1291 1292 1293 1294 1295
    SafeArrayGetLBound(V_ARRAY(&v), 1, &bound);
    SafeArrayGetLBound(V_ARRAY(&v2), 1, &bound2);
    ok(bound == bound2, "array lbounds differ\n");
    SafeArrayGetUBound(V_ARRAY(&v), 1, &bound);
    SafeArrayGetUBound(V_ARRAY(&v2), 1, &bound2);
    ok(bound == bound2, "array ubounds differ\n");
1296 1297 1298 1299 1300 1301
    if (pSafeArrayGetVartype)
    {
        pSafeArrayGetVartype(V_ARRAY(&v), &vt);
        pSafeArrayGetVartype(V_ARRAY(&v2), &vt2);
        ok(vt == vt2, "array vts differ %x %x\n", vt, vt2);
    }
1302
    VARIANT_UserFree(&umcb.Flags, &v2);
1303
    HeapFree(GetProcessHeap(), 0, oldbuffer);
1304 1305 1306 1307 1308 1309

    /*** ARRAY BYREF ***/
    VariantInit(&v);
    V_VT(&v) = VT_UI4 | VT_ARRAY | VT_BYREF;
    V_ARRAYREF(&v) = &lpsa;

1310
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
1311 1312 1313
    expected = 152;
    ok(stubMsg.BufferLength == expected || stubMsg.BufferLength == expected + 16, /* win64 */
       "size %u instead of %u\n", stubMsg.BufferLength, expected);
1314
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
1315
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
1316
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
1317
    ok(next == buffer + expected, "got %p expect %p\n", next, buffer + expected);
1318
    wirev = (DWORD*)buffer;
1319

1320
    wirev = check_variant_header(wirev, &v, expected);
1321
    ok(*wirev == 4, "wv[5] %08x\n", *wirev);
1322
    wirev++;
1323
    ok(*wirev, "wv[6] %08x\n", *wirev); /* win2k: this is lpsa. winxp: this is (char*)lpsa + 1 */
1324 1325
    wirev++;
    check_safearray(wirev, lpsa);
1326 1327 1328 1329 1330
    VariantInit(&v2);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + expected, "got %p expect %p\n", next, buffer + expected);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
1331
    ok(SafeArrayGetDim(*V_ARRAYREF(&v)) == SafeArrayGetDim(*V_ARRAYREF(&v2)), "array dims differ\n");
1332 1333 1334 1335 1336 1337
    SafeArrayGetLBound(*V_ARRAYREF(&v), 1, &bound);
    SafeArrayGetLBound(*V_ARRAYREF(&v2), 1, &bound2);
    ok(bound == bound2, "array lbounds differ\n");
    SafeArrayGetUBound(*V_ARRAYREF(&v), 1, &bound);
    SafeArrayGetUBound(*V_ARRAYREF(&v2), 1, &bound2);
    ok(bound == bound2, "array ubounds differ\n");
1338 1339 1340 1341 1342 1343
    if (pSafeArrayGetVartype)
    {
        pSafeArrayGetVartype(*V_ARRAYREF(&v), &vt);
        pSafeArrayGetVartype(*V_ARRAYREF(&v2), &vt2);
        ok(vt == vt2, "array vts differ %x %x\n", vt, vt2);
    }
1344
    VARIANT_UserFree(&umcb.Flags, &v2);
1345
    HeapFree(GetProcessHeap(), 0, oldbuffer);
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378

    /*** ARRAY BYREF ***/
    VariantInit(&v);
    V_VT(&v) = VT_UI4 | VT_ARRAY | VT_BYREF;
    V_ARRAYREF(&v) = &lpsa;
    lpsa->fFeatures |= FADF_STATIC;

    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    expected = 152;
    ok(stubMsg.BufferLength == expected || stubMsg.BufferLength == expected + 16, /* win64 */
       "size %u instead of %u\n", stubMsg.BufferLength, expected);
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
    ok(next == buffer + expected, "got %p expect %p\n", next, buffer + expected);
    wirev = (DWORD*)buffer;

    wirev = check_variant_header(wirev, &v, expected);
    ok(*wirev == 4, "wv[5] %08x\n", *wirev);
    wirev++;
    ok(*wirev, "wv[6] %08x\n", *wirev); /* win2k: this is lpsa. winxp: this is (char*)lpsa + 1 */
    wirev++;
    check_safearray(wirev, lpsa);
    lpsa_copy = lpsa2 = SafeArrayCreate(VT_I8, 1, &sab);
    /* set FADF_STATIC feature to make sure lpsa2->pvData pointer changes if new data buffer is allocated */
    lpsa2->fFeatures |= FADF_STATIC;
    mem = lpsa2->pvData;
    V_VT(&v2) = VT_UI4 | VT_ARRAY | VT_BYREF;
    V_ARRAYREF(&v2) = &lpsa2;
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(next == buffer + expected, "got %p expect %p\n", next, buffer + expected);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
1379
    ok(lpsa2 == lpsa_copy, "safearray should be reused\n");
1380
    ok(mem == lpsa2->pvData, "safearray data should be reused\n");
1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398
    ok(SafeArrayGetDim(*V_ARRAYREF(&v)) == SafeArrayGetDim(*V_ARRAYREF(&v2)), "array dims differ\n");
    SafeArrayGetLBound(*V_ARRAYREF(&v), 1, &bound);
    SafeArrayGetLBound(*V_ARRAYREF(&v2), 1, &bound2);
    ok(bound == bound2, "array lbounds differ\n");
    SafeArrayGetUBound(*V_ARRAYREF(&v), 1, &bound);
    SafeArrayGetUBound(*V_ARRAYREF(&v2), 1, &bound2);
    ok(bound == bound2, "array ubounds differ\n");
    if (pSafeArrayGetVartype)
    {
        pSafeArrayGetVartype(*V_ARRAYREF(&v), &vt);
        pSafeArrayGetVartype(*V_ARRAYREF(&v2), &vt2);
        ok(vt == vt2, "array vts differ %x %x\n", vt, vt2);
    }
    lpsa2->fFeatures &= ~FADF_STATIC;
    hr = SafeArrayDestroy(*V_ARRAYREF(&v2));
    ok(hr == S_OK, "got 0x%08x\n", hr);
    HeapFree(GetProcessHeap(), 0, oldbuffer);
    lpsa->fFeatures &= ~FADF_STATIC;
1399 1400
    hr = SafeArrayDestroy(lpsa);
    ok(hr == S_OK, "got 0x%08x\n", hr);
1401 1402 1403 1404 1405 1406 1407 1408 1409

    /*** VARIANT BYREF ***/
    VariantInit(&v);
    VariantInit(&v2);
    V_VT(&v2) = VT_R8;
    V_R8(&v2) = 3.1415;
    V_VT(&v) = VT_VARIANT | VT_BYREF;
    V_VARIANTREF(&v) = &v2;

1410 1411
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength == 64, "size %d\n", stubMsg.BufferLength);
1412
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
1413 1414
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
    memset(buffer, 0xcc, stubMsg.BufferLength);
1415
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
1416
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
1417
    wirev = (DWORD*)buffer;
1418
    wirev = check_variant_header(wirev, &v, stubMsg.BufferLength);
1419

1420
    ok(*wirev == sizeof(VARIANT), "wv[5] %08x\n", *wirev);
1421
    wirev++;
1422
    ok(*wirev == ('U' | 's' << 8 | 'e' << 16 | 'r' << 24), "wv[6] %08x\n", *wirev); /* 'User' */
1423
    wirev++;
1424
    ok(*wirev == 0xcccccccc, "wv[7] %08x\n", *wirev); /* pad */
1425
    wirev++;
1426
    wirev = check_variant_header(wirev, &v2, stubMsg.BufferLength - 32);
1427
    ok(*wirev == 0xcccccccc, "wv[13] %08x\n", *wirev); /* pad for VT_R8 */
1428
    wirev++;
1429
    ok(*(double*)wirev == V_R8(&v2), "wv[6] %08x wv[7] %08x\n", *wirev, *(wirev+1));
1430 1431 1432 1433 1434 1435 1436 1437 1438
    VariantInit(&v3);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v3);
    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
    ok(V_VT(&v) == V_VT(&v3), "got vt %d expect %d\n", V_VT(&v), V_VT(&v3));
    ok(V_VT(V_VARIANTREF(&v)) == V_VT(V_VARIANTREF(&v3)), "vts differ %x %x\n",
       V_VT(V_VARIANTREF(&v)), V_VT(V_VARIANTREF(&v3))); 
    ok(V_R8(V_VARIANTREF(&v)) == V_R8(V_VARIANTREF(&v3)), "r8s differ\n"); 
    VARIANT_UserFree(&umcb.Flags, &v3);
1439
    HeapFree(GetProcessHeap(), 0, oldbuffer);
1440 1441 1442

    /*** UNKNOWN ***/
    heap_unknown = HeapAlloc(GetProcessHeap(), 0, sizeof(*heap_unknown));
1443
    heap_unknown->IUnknown_iface.lpVtbl = &HeapUnknown_Vtbl;
1444 1445 1446 1447
    heap_unknown->refs = 1;
    VariantInit(&v);
    VariantInit(&v2);
    V_VT(&v) = VT_UNKNOWN;
1448
    V_UNKNOWN(&v) = &heap_unknown->IUnknown_iface;
1449

1450
    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
1451
    ok(stubMsg.BufferLength > 40, "size %d\n", stubMsg.BufferLength);
1452
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
1453 1454
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
    memset(buffer, 0xcc, stubMsg.BufferLength);
1455
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
1456 1457
todo_wine
    ok(heap_unknown->refs == 2, "got refcount %d\n", heap_unknown->refs);
1458
    wirev = (DWORD*)buffer;
1459
    wirev = check_variant_header(wirev, &v, next - buffer);
1460

1461 1462
    ok(*wirev == (DWORD_PTR)V_UNKNOWN(&v) /* Win9x */ ||
       *wirev == (DWORD_PTR)V_UNKNOWN(&v) + 1 /* NT */, "wv[5] %08x\n", *wirev);
1463 1464 1465 1466 1467 1468
    wirev++;
    ok(*wirev == next - buffer - 0x20, "wv[6] %08x\n", *wirev);
    wirev++;
    ok(*wirev == next - buffer - 0x20, "wv[7] %08x\n", *wirev);
    wirev++;
    ok(*wirev == 0x574f454d, "wv[8] %08x\n", *wirev);
1469 1470 1471 1472 1473
    VariantInit(&v3);
    V_VT(&v3) = VT_UNKNOWN;
    V_UNKNOWN(&v3) = &heap_unknown->IUnknown_iface;
    IUnknown_AddRef(V_UNKNOWN(&v3));
    stubMsg.Buffer = buffer;
1474 1475
todo_wine
    ok(heap_unknown->refs == 3, "got refcount %d\n", heap_unknown->refs);
1476 1477 1478 1479 1480 1481
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v3);
    ok(V_VT(&v) == V_VT(&v3), "got vt %d expect %d\n", V_VT(&v), V_VT(&v3));
    ok(V_UNKNOWN(&v) == V_UNKNOWN(&v3), "got %p expect %p\n", V_UNKNOWN(&v), V_UNKNOWN(&v3));
    VARIANT_UserFree(&umcb.Flags, &v3);
    ok(heap_unknown->refs == 1, "%d refcounts of IUnknown leaked\n", heap_unknown->refs - 1);
    IUnknown_Release(&heap_unknown->IUnknown_iface);
1482
    HeapFree(GetProcessHeap(), 0, oldbuffer);
1483

1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495
    /*** NULL UNKNOWN ***/
    VariantInit(&v);
    V_VT(&v) = VT_UNKNOWN;
    V_UNKNOWN(&v) = NULL;

    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
    ok(stubMsg.BufferLength >= 24, "size %d\n", stubMsg.BufferLength);
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
    memset(buffer, 0xcc, stubMsg.BufferLength);
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
    wirev = (DWORD*)buffer;
1496
    wirev = check_variant_header(wirev, &v, next - buffer);
1497 1498 1499 1500 1501 1502 1503 1504 1505 1506
    ok(*wirev == 0, "wv[5] %08x\n", *wirev);

    VariantInit(&v2);
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
    ok(V_UNKNOWN(&v2) == NULL, "got %p expect NULL\n", V_UNKNOWN(&v2));
    VARIANT_UserFree(&umcb.Flags, &v2);
    HeapFree(GetProcessHeap(), 0, oldbuffer);

1507 1508
    /*** UNKNOWN BYREF ***/
    heap_unknown = HeapAlloc(GetProcessHeap(), 0, sizeof(*heap_unknown));
1509
    heap_unknown->IUnknown_iface.lpVtbl = &HeapUnknown_Vtbl;
1510 1511 1512 1513 1514 1515 1516
    heap_unknown->refs = 1;
    VariantInit(&v);
    VariantInit(&v2);
    V_VT(&v) = VT_UNKNOWN | VT_BYREF;
    V_UNKNOWNREF(&v) = (IUnknown **)&heap_unknown;

    rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
1517
    ok(stubMsg.BufferLength >= 44, "size %d\n", stubMsg.BufferLength);
1518
    buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
1519 1520
    stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
    memset(buffer, 0xcc, stubMsg.BufferLength);
1521
    ok(heap_unknown->refs == 1, "got refcount %d\n", heap_unknown->refs);
1522
    next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
1523 1524
todo_wine
    ok(heap_unknown->refs == 2, "got refcount %d\n", heap_unknown->refs);
1525
    wirev = (DWORD*)buffer;
1526
    wirev = check_variant_header(wirev, &v, next - buffer);
1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537

    ok(*wirev == 4, "wv[5] %08x\n", *wirev);
    wirev++;
    ok(*wirev == (DWORD_PTR)heap_unknown /* Win9x, Win2000 */ ||
       *wirev == (DWORD_PTR)heap_unknown + 1 /* XP */, "wv[6] %08x\n", *wirev);
    wirev++;
    ok(*wirev == next - buffer - 0x24, "wv[7] %08x\n", *wirev);
    wirev++;
    ok(*wirev == next - buffer - 0x24, "wv[8] %08x\n", *wirev);
    wirev++;
    ok(*wirev == 0x574f454d, "wv[9] %08x\n", *wirev);
1538 1539 1540 1541 1542 1543 1544

    VariantInit(&v3);
    V_VT(&v3) = VT_UNKNOWN;
    V_UNKNOWN(&v3) = &heap_unknown->IUnknown_iface;
    IUnknown_AddRef(V_UNKNOWN(&v3));
    stubMsg.Buffer = buffer;
    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v3);
1545
    ok(heap_unknown->refs == 2, "got refcount %d\n", heap_unknown->refs);
1546 1547 1548 1549 1550
    ok(V_VT(&v) == V_VT(&v3), "got vt %d expect %d\n", V_VT(&v), V_VT(&v3));
    ok(*V_UNKNOWNREF(&v) == *V_UNKNOWNREF(&v3), "got %p expect %p\n", *V_UNKNOWNREF(&v), *V_UNKNOWNREF(&v3));
    VARIANT_UserFree(&umcb.Flags, &v3);
    ok(heap_unknown->refs == 1, "%d refcounts of IUnknown leaked\n", heap_unknown->refs - 1);
    IUnknown_Release(&heap_unknown->IUnknown_iface);
1551
    HeapFree(GetProcessHeap(), 0, oldbuffer);
1552 1553 1554
}


1555 1556
START_TEST(usrmarshal)
{
1557 1558 1559 1560 1561 1562 1563 1564 1565 1566
    HANDLE hOleaut32 = GetModuleHandleA("oleaut32.dll");
#define GETPTR(func) p##func = (void*)GetProcAddress(hOleaut32, #func)
    GETPTR(SafeArrayGetIID);
    GETPTR(SafeArrayGetVartype);
    GETPTR(VarBstrCmp);
#undef GETPTR

    if (!pSafeArrayGetIID || !pSafeArrayGetVartype)
        win_skip("SafeArrayGetIID and/or SafeArrayGetVartype is not available, some tests will be skipped\n");

1567 1568 1569
    CoInitialize(NULL);

    test_marshal_LPSAFEARRAY();
1570
    test_marshal_BSTR();
1571
    test_marshal_VARIANT();
1572 1573 1574

    CoUninitialize();
}