oleaut32: Split out the SAFEARRAY and BSTR tests so that they can be used in the...
[wine] / dlls / oleaut32 / tests / usrmarshal.c
1 /*
2  * Marshaling Tests
3  *
4  * Copyright 2004 Robert Shearman
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "objbase.h"
26 #include "propidl.h" /* for LPSAFEARRAY_User* routines */
27
28 #include "wine/test.h"
29
30 /* doesn't work on Windows due to needing more of the
31  * MIDL_STUB_MESSAGE structure to be filled out */
32 #define LPSAFEARRAY_UNMARSHAL_WORKS 0
33 #define BSTR_UNMARSHAL_WORKS 0
34
35 static inline SF_TYPE get_union_type(SAFEARRAY *psa)
36 {
37     VARTYPE vt;
38     HRESULT hr;
39
40     hr = SafeArrayGetVartype(psa, &vt);
41     if (FAILED(hr))
42         return 0;
43
44     if (psa->fFeatures & FADF_HAVEIID)
45         return SF_HAVEIID;
46
47     switch (vt)
48     {
49     case VT_I1:
50     case VT_UI1:      return SF_I1;
51     case VT_BOOL:
52     case VT_I2:
53     case VT_UI2:      return SF_I2;
54     case VT_INT:
55     case VT_UINT:
56     case VT_I4:
57     case VT_UI4:
58     case VT_R4:       return SF_I4;
59     case VT_DATE:
60     case VT_CY:
61     case VT_R8:
62     case VT_I8:
63     case VT_UI8:      return SF_I8;
64     case VT_INT_PTR:
65     case VT_UINT_PTR: return (sizeof(UINT_PTR) == 4 ? SF_I4 : SF_I8);
66     case VT_BSTR:     return SF_BSTR;
67     case VT_DISPATCH: return SF_DISPATCH;
68     case VT_VARIANT:  return SF_VARIANT;
69     case VT_UNKNOWN:  return SF_UNKNOWN;
70     /* Note: Return a non-zero size to indicate vt is valid. The actual size
71      * of a UDT is taken from the result of IRecordInfo_GetSize().
72      */
73     case VT_RECORD:   return SF_RECORD;
74     default:          return SF_ERROR;
75     }
76 }
77
78 static ULONG get_cell_count(const SAFEARRAY *psa)
79 {
80     const SAFEARRAYBOUND* psab = psa->rgsabound;
81     USHORT cCount = psa->cDims;
82     ULONG ulNumCells = 1;
83
84     while (cCount--)
85     {
86          if (!psab->cElements)
87             return 0;
88         ulNumCells *= psab->cElements;
89         psab++;
90     }
91     return ulNumCells;
92 }
93
94 static void check_safearray(void *buffer, LPSAFEARRAY lpsa)
95 {
96     unsigned char *wiresa = buffer;
97     VARTYPE vt;
98     SF_TYPE sftype;
99     ULONG cell_count;
100
101     if(!lpsa)
102     {
103         ok(*(DWORD *)wiresa == FALSE, "wiresa + 0x0 should be FALSE instead of 0x%08lx\n", *(DWORD *)wiresa);
104         return;
105     }
106
107     SafeArrayGetVartype(lpsa, &vt);
108     sftype = get_union_type(lpsa);
109     cell_count = get_cell_count(lpsa);
110
111     ok(*(DWORD *)wiresa == TRUE, "wiresa + 0x0 should be TRUE instead of 0x%08lx\n", *(DWORD *)wiresa);
112     wiresa += sizeof(DWORD);
113     ok(*(DWORD *)wiresa == lpsa->cDims, "wiresa + 0x4 should be lpsa->cDims instead of 0x%08lx\n", *(DWORD *)wiresa);
114     wiresa += sizeof(DWORD);
115     ok(*(WORD *)wiresa == lpsa->cDims, "wiresa + 0x8 should be lpsa->cDims instead of 0x%04x\n", *(WORD *)wiresa);
116     wiresa += sizeof(WORD);
117     ok(*(WORD *)wiresa == lpsa->fFeatures, "wiresa + 0xc should be lpsa->fFeatures instead of 0x%08x\n", *(WORD *)wiresa);
118     wiresa += sizeof(WORD);
119     ok(*(DWORD *)wiresa == lpsa->cbElements, "wiresa + 0x10 should be lpsa->cbElements instead of 0x%08lx\n", *(DWORD *)wiresa);
120     wiresa += sizeof(DWORD);
121     ok(*(WORD *)wiresa == lpsa->cLocks, "wiresa + 0x16 should be lpsa->cLocks instead of 0x%04x\n", *(WORD *)wiresa);
122     wiresa += sizeof(WORD);
123     ok(*(WORD *)wiresa == vt, "wiresa + 0x14 should be %04x instead of 0x%04x\n", vt, *(WORD *)wiresa);
124     wiresa += sizeof(WORD);
125     ok(*(DWORD *)wiresa == sftype, "wiresa + 0x18 should be %08lx instead of 0x%08lx\n", (DWORD)sftype, *(DWORD *)wiresa);
126     wiresa += sizeof(DWORD);
127     ok(*(DWORD *)wiresa == cell_count, "wiresa + 0x1c should be %lu instead of %lu\n", cell_count, *(DWORD *)wiresa);
128     wiresa += sizeof(DWORD);
129     ok(*(DWORD_PTR *)wiresa == (DWORD_PTR)lpsa->pvData, "wirestgm + 0x20 should be lpsa->pvData instead of 0x%08lx\n", *(DWORD_PTR *)wiresa);
130     wiresa += sizeof(DWORD_PTR);
131     if(sftype == SF_HAVEIID)
132     {
133         GUID guid;
134         SafeArrayGetIID(lpsa, &guid);
135         ok(IsEqualGUID(&guid, (GUID*)wiresa), "guid mismatch\n");
136         wiresa += sizeof(GUID);
137     }
138     ok(!memcmp(wiresa, lpsa->rgsabound, sizeof(lpsa->rgsabound[0]) * lpsa->cDims), "bounds mismatch\n");
139     wiresa += sizeof(lpsa->rgsabound[0]) * lpsa->cDims;
140
141     ok(*(DWORD *)wiresa == cell_count, "wiresa + 0x2c should be %lu instead of %lu\n", cell_count, *(DWORD*)wiresa);
142     wiresa += sizeof(DWORD);
143     /* elements are now pointed to by wiresa */
144 }
145
146 static void test_marshal_LPSAFEARRAY(void)
147 {
148     unsigned char *buffer;
149     unsigned long size;
150     LPSAFEARRAY lpsa;
151     LPSAFEARRAY lpsa2 = NULL;
152     SAFEARRAYBOUND sab;
153     MIDL_STUB_MESSAGE stubMsg = { 0 };
154     USER_MARSHAL_CB umcb = { 0 };
155
156     umcb.Flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
157     umcb.pReserve = NULL;
158     umcb.pStubMsg = &stubMsg;
159
160     sab.lLbound = 5;
161     sab.cElements = 10;
162
163     lpsa = SafeArrayCreate(VT_I2, 1, &sab);
164     *(DWORD *)lpsa->pvData = 0xcafebabe;
165
166     lpsa->cLocks = 7;
167     size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa);
168     ok(size == 64, "size should be 64 bytes, not %ld\n", size);
169     buffer = (unsigned char *)HeapAlloc(GetProcessHeap(), 0, size);
170     LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa);
171
172     check_safearray(buffer, lpsa);
173
174     if (LPSAFEARRAY_UNMARSHAL_WORKS)
175     {
176         LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2);
177         ok(lpsa2 != NULL, "LPSAFEARRAY didn't unmarshal\n");
178         LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2);
179     }
180     HeapFree(GetProcessHeap(), 0, buffer);
181     SafeArrayDestroy(lpsa);
182
183     /* test NULL safe array */
184     lpsa = NULL;
185
186     size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa);
187     ok(size == 4, "size should be 4 bytes, not %ld\n", size);
188     buffer = (unsigned char *)HeapAlloc(GetProcessHeap(), 0, size);
189     LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa);
190     check_safearray(buffer, lpsa);
191
192     if (LPSAFEARRAY_UNMARSHAL_WORKS)
193     {
194         LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2);
195         ok(lpsa2 == NULL, "NULL LPSAFEARRAY didn't unmarshal\n");
196         LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2);
197     }
198     HeapFree(GetProcessHeap(), 0, buffer);
199 }
200
201 static void check_bstr(void *buffer, BSTR b)
202 {
203     DWORD *wireb = buffer;
204     DWORD len = SysStringLen(b);
205
206     ok(*wireb == len, "wv[0] %08lx\n", *wireb);
207     wireb++;
208     if(len)
209         ok(*wireb == len * 2, "wv[1] %08lx\n", *wireb);
210     else
211         ok(*wireb == 0xffffffff, "wv[1] %08lx\n", *wireb);
212     wireb++;
213     ok(*wireb == len, "wv[2] %08lx\n", *wireb);
214     if(len)
215     {
216         wireb++;
217         ok(!memcmp(wireb, b, len * 2), "strings differ\n");
218     }
219     return;
220 }
221
222 static void test_marshal_BSTR(void)
223 {
224     unsigned long size;
225     MIDL_STUB_MESSAGE stubMsg = { 0 };
226     USER_MARSHAL_CB umcb = { 0 };
227     unsigned char *buffer;
228     BSTR b, b2;
229     WCHAR str[] = {'m','a','r','s','h','a','l',' ','t','e','s','t','1',0};
230     DWORD len;
231
232     umcb.Flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
233     umcb.pReserve = NULL;
234     umcb.pStubMsg = &stubMsg;
235
236     b = SysAllocString(str);
237     len = SysStringLen(b);
238     ok(len == 13, "get %ld\n", len);
239
240     /* BSTRs are DWORD aligned */
241     size = BSTR_UserSize(&umcb.Flags, 1, &b);
242     ok(size == 42, "size %ld\n", size);
243
244     size = BSTR_UserSize(&umcb.Flags, 0, &b);
245     ok(size == 38, "size %ld\n", size);
246
247     buffer = HeapAlloc(GetProcessHeap(), 0, size);
248     BSTR_UserMarshal(&umcb.Flags, buffer, &b);
249     check_bstr(buffer, b);
250
251     if (BSTR_UNMARSHAL_WORKS)
252     {
253         b2 = NULL;
254         BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2);
255         ok(b2 != NULL, "NULL LPSAFEARRAY didn't unmarshal\n");
256         ok(!memcmp(b, b2, (len + 1) * 2), "strings differ\n");
257         BSTR_UserFree(&umcb.Flags, &b2);
258     }
259
260     HeapFree(GetProcessHeap(), 0, buffer);
261     SysFreeString(b);
262
263     b = NULL;
264     size = BSTR_UserSize(&umcb.Flags, 0, &b);
265     ok(size == 12, "size %ld\n", size);
266
267     buffer = HeapAlloc(GetProcessHeap(), 0, size);
268     BSTR_UserMarshal(&umcb.Flags, buffer, &b);
269
270     check_bstr(buffer, b);
271     HeapFree(GetProcessHeap(), 0, buffer);
272
273 }
274
275 START_TEST(usrmarshal)
276 {
277     CoInitialize(NULL);
278
279     test_marshal_LPSAFEARRAY();
280     test_marshal_BSTR();
281
282     CoUninitialize();
283 }