msdaps: Add support for remoting IRowsetInfo_GetProperties.
[wine] / dlls / msdaps / row_server.c
1 /*
2  *    Row and rowset servers / proxies.
3  *
4  * Copyright 2010 Huw Davies
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 #include <stdarg.h>
21 #include <string.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winerror.h"
32 #include "objbase.h"
33 #include "oleauto.h"
34 #include "oledb.h"
35
36 #include "row_server.h"
37
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(oledb);
41
42 static inline DBLENGTH db_type_size(DBTYPE type, DBLENGTH var_len)
43 {
44     switch(type)
45     {
46     case DBTYPE_I1:
47     case DBTYPE_UI1:
48         return 1;
49     case DBTYPE_I2:
50     case DBTYPE_UI2:
51         return 2;
52     case DBTYPE_I4:
53     case DBTYPE_UI4:
54     case DBTYPE_R4:
55         return 4;
56     case DBTYPE_I8:
57     case DBTYPE_UI8:
58     case DBTYPE_R8:
59         return 8;
60     case DBTYPE_CY:
61         return sizeof(CY);
62     case DBTYPE_FILETIME:
63         return sizeof(FILETIME);
64     case DBTYPE_BSTR:
65         return sizeof(BSTR);
66     case DBTYPE_GUID:
67         return sizeof(GUID);
68     case DBTYPE_WSTR:
69         return var_len;
70     default:
71         FIXME("Unhandled type %04x\n", type);
72         return 0;
73     }
74 }
75
76 typedef struct
77 {
78     const IWineRowServerVtbl *vtbl;
79
80     LONG ref;
81
82     CLSID class;
83     IMarshal *marshal;
84     IUnknown *inner_unk;
85 } server;
86
87 static inline server *impl_from_IWineRowServer(IWineRowServer *iface)
88 {
89     return (server *)((char*)iface - FIELD_OFFSET(server, vtbl));
90 }
91
92 static HRESULT WINAPI server_QueryInterface(IWineRowServer *iface, REFIID riid, void **obj)
93 {
94     server *This = impl_from_IWineRowServer(iface);
95     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
96
97     *obj = NULL;
98
99     if(IsEqualIID(riid, &IID_IUnknown) ||
100        IsEqualIID(riid, &IID_IWineRowServer))
101     {
102         *obj = iface;
103     }
104     else
105     {
106         if(!IsEqualIID(riid, &IID_IMarshal)) /* We use standard marshalling */
107             FIXME("interface %s not implemented\n", debugstr_guid(riid));
108         return E_NOINTERFACE;
109     }
110
111     IWineRowServer_AddRef(iface);
112     return S_OK;
113 }
114
115 static ULONG WINAPI server_AddRef(IWineRowServer *iface)
116 {
117     server *This = impl_from_IWineRowServer(iface);
118     TRACE("(%p)\n", This);
119
120     return InterlockedIncrement(&This->ref);
121 }
122
123 static ULONG WINAPI server_Release(IWineRowServer *iface)
124 {
125     server *This = impl_from_IWineRowServer(iface);
126     LONG ref;
127
128     TRACE("(%p)\n", This);
129
130     ref = InterlockedDecrement(&This->ref);
131     if(ref == 0)
132     {
133         IMarshal_Release(This->marshal);
134         if(This->inner_unk) IUnknown_Release(This->inner_unk);
135         HeapFree(GetProcessHeap(), 0, This);
136     }
137
138     return ref;
139 }
140
141 static HRESULT WINAPI server_SetInnerUnk(IWineRowServer *iface, IUnknown *inner)
142 {
143     server *This = impl_from_IWineRowServer(iface);
144
145     if(This->inner_unk) IUnknown_Release(This->inner_unk);
146
147     if(inner) IUnknown_AddRef(inner);
148     This->inner_unk = inner;
149     return S_OK;
150 }
151
152 static HRESULT WINAPI server_GetMarshal(IWineRowServer *iface, IMarshal **marshal)
153 {
154     server *This = impl_from_IWineRowServer(iface);
155
156     IMarshal_AddRef(This->marshal);
157     *marshal = This->marshal;
158     return S_OK;
159 }
160
161 static HRESULT WINAPI server_GetColumns(IWineRowServer* iface, DBORDINAL num_cols,
162                                         wine_getcolumns_in *in_data, wine_getcolumns_out *out_data)
163 {
164     server *This = impl_from_IWineRowServer(iface);
165     HRESULT hr;
166     DBORDINAL i;
167     DBCOLUMNACCESS *cols;
168     IRow *row;
169
170     TRACE("(%p)->(%d, %p, %p)\n", This, num_cols, in_data, out_data);
171
172     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRow, (void**)&row);
173     if(FAILED(hr)) return hr;
174
175     cols = CoTaskMemAlloc(num_cols * sizeof(cols[0]));
176
177     for(i = 0; i < num_cols; i++)
178     {
179         TRACE("%d:\tmax_len %d type %04x\n", i, in_data[i].max_len, in_data[i].type);
180         cols[i].pData        = CoTaskMemAlloc(db_type_size(in_data[i].type, in_data[i].max_len));
181         cols[i].columnid     = in_data[i].columnid;
182         cols[i].cbMaxLen     = in_data[i].max_len;
183         cols[i].wType        = in_data[i].type;
184         cols[i].bPrecision   = in_data[i].precision;
185         cols[i].bScale       = in_data[i].scale;
186     }
187
188     hr = IRow_GetColumns(row, num_cols, cols);
189     IRow_Release(row);
190
191     for(i = 0; i < num_cols; i++)
192     {
193         VariantInit(&out_data[i].v);
194         if(cols[i].dwStatus == DBSTATUS_S_OK)
195         {
196             V_VT(&out_data[i].v) = in_data[i].type;
197             memcpy(&V_I1(&out_data[i].v), cols[i].pData, cols[i].cbDataLen);
198         }
199         CoTaskMemFree(cols[i].pData);
200         out_data[i].data_len = cols[i].cbDataLen;
201         out_data[i].status   = cols[i].dwStatus;
202     }
203
204     CoTaskMemFree(cols);
205
206     return hr;
207 }
208
209 static HRESULT WINAPI server_GetSourceRowset(IWineRowServer* iface, REFIID riid, IUnknown **ppRowset,
210                                              HROW *phRow)
211 {
212     server *This = impl_from_IWineRowServer(iface);
213     FIXME("(%p): stub\n", This);
214     return E_NOTIMPL;
215 }
216
217 static HRESULT WINAPI server_Open(IWineRowServer* iface, IUnknown *pUnkOuter, DBID *pColumnID,
218                                   REFGUID rguidColumnType, DWORD dwBindFlags, REFIID riid,
219                                   IUnknown **ppUnk)
220 {
221     server *This = impl_from_IWineRowServer(iface);
222
223     FIXME("(%p)->(%p, %p, %s, %08x, %s, %p): stub\n", This, pUnkOuter, pColumnID, debugstr_guid(rguidColumnType),
224           dwBindFlags, debugstr_guid(riid), ppUnk);
225     return E_NOTIMPL;
226 }
227
228 static HRESULT WINAPI server_SetColumns(IWineRowServer* iface, DBORDINAL num_cols,
229                                         wine_setcolumns_in *in_data, DBSTATUS *status)
230 {
231     server *This = impl_from_IWineRowServer(iface);
232     FIXME("(%p)->(%d, %p, %p): stub\n", This, num_cols, in_data, status);
233     return E_NOTIMPL;
234 }
235
236 static HRESULT WINAPI server_AddRefRows(IWineRowServer* iface, DBCOUNTITEM cRows,
237                                         const HROW rghRows[], DBREFCOUNT rgRefCounts[],
238                                         DBROWSTATUS rgRowStatus[])
239 {
240     server *This = impl_from_IWineRowServer(iface);
241     IRowset *rowset;
242     HRESULT hr;
243
244     TRACE("(%p)->(%d, %p, %p, %p)\n", This, cRows, rghRows, rgRefCounts, rgRowStatus);
245
246     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowset, (void**)&rowset);
247     if(FAILED(hr)) return hr;
248
249     hr = IRowset_AddRefRows(rowset, cRows, rghRows, rgRefCounts, rgRowStatus);
250
251     IRowset_Release(rowset);
252     TRACE("returning %08x\n", hr);
253     return hr;
254 }
255
256 static HRESULT WINAPI server_GetData(IWineRowServer* iface, HROW hRow,
257                                      HACCESSOR hAccessor, BYTE *pData, DWORD size)
258 {
259     server *This = impl_from_IWineRowServer(iface);
260     FIXME("(%p)->(%08lx, %08lx, %p, %d): stub\n", This, hRow, hAccessor, pData, size);
261     return E_NOTIMPL;
262 }
263
264 static HRESULT WINAPI server_GetNextRows(IWineRowServer* iface, HCHAPTER hReserved, DBROWOFFSET lRowsOffset,
265                                          DBROWCOUNT cRows, DBCOUNTITEM *pcRowObtained, HROW **prghRows)
266 {
267     server *This = impl_from_IWineRowServer(iface);
268     IRowset *rowset;
269     HRESULT hr;
270
271     TRACE("(%p)->(%08lx, %d, %d, %p, %p)\n", This, hReserved, lRowsOffset, cRows, pcRowObtained, prghRows);
272
273     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowset, (void**)&rowset);
274     if(FAILED(hr)) return hr;
275
276     *prghRows = NULL;
277
278     hr = IRowset_GetNextRows(rowset, hReserved, lRowsOffset, cRows, pcRowObtained, prghRows);
279     IRowset_Release(rowset);
280     TRACE("returning %08x, got %d rows\n", hr, *pcRowObtained);
281     return hr;
282 }
283
284 static HRESULT WINAPI server_ReleaseRows(IWineRowServer* iface, DBCOUNTITEM cRows, const HROW rghRows[],
285                                          DBROWOPTIONS rgRowOptions[], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[])
286 {
287     server *This = impl_from_IWineRowServer(iface);
288     IRowset *rowset;
289     HRESULT hr;
290
291     TRACE("(%p)->(%d, %p, %p, %p, %p)\n", This, cRows, rghRows, rgRowOptions, rgRefCounts, rgRowStatus);
292
293     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowset, (void**)&rowset);
294     if(FAILED(hr)) return hr;
295
296     hr = IRowset_ReleaseRows(rowset, cRows, rghRows, rgRowOptions, rgRefCounts, rgRowStatus);
297     IRowset_Release(rowset);
298
299     TRACE("returning %08x\n", hr);
300     return hr;
301 }
302
303 static HRESULT WINAPI server_RestartPosition(IWineRowServer* iface, HCHAPTER hReserved)
304 {
305     server *This = impl_from_IWineRowServer(iface);
306     FIXME("(%p)->(%08lx): stub\n", This, hReserved);
307     return E_NOTIMPL;
308 }
309
310 static HRESULT WINAPI server_Compare(IWineRowServer *iface, HCHAPTER hReserved, DBBKMARK cbBookmark1,
311                                      const BYTE *pBookmark1, DBBKMARK cbBookmark2, const BYTE *pBookmark2,
312                                      DBCOMPARE *pComparison)
313 {
314     server *This = impl_from_IWineRowServer(iface);
315     FIXME("(%p): stub\n", This);
316     return E_NOTIMPL;
317 }
318
319 static HRESULT WINAPI server_GetRowsAt(IWineRowServer *iface, HWATCHREGION hReserved1, HCHAPTER hReserved2,
320                                        DBBKMARK cbBookmark, const BYTE *pBookmark, DBROWOFFSET lRowsOffset,
321                                        DBROWCOUNT cRows, DBCOUNTITEM *pcRowsObtained, HROW **prghRows)
322 {
323     server *This = impl_from_IWineRowServer(iface);
324
325     FIXME("(%p)->(%08lx, %08lx, %d, %p, %d, %d, %p, %p): stub\n", This, hReserved1, hReserved2, cbBookmark, pBookmark,
326           lRowsOffset, cRows, pcRowsObtained, prghRows);
327
328     return E_NOTIMPL;
329 }
330
331 static HRESULT WINAPI server_GetRowsByBookmark(IWineRowServer *iface, HCHAPTER hReserved, DBCOUNTITEM cRows,
332                                                const DBBKMARK rgcbBookmarks[], const BYTE * rgpBookmarks[],
333                                                HROW rghRows[], DBROWSTATUS rgRowStatus[])
334 {
335     server *This = impl_from_IWineRowServer(iface);
336     FIXME("(%p): stub\n", This);
337     return E_NOTIMPL;
338 }
339
340 static HRESULT WINAPI server_Hash(IWineRowServer *iface, HCHAPTER hReserved, DBBKMARK cBookmarks,
341                                   const DBBKMARK rgcbBookmarks[], const BYTE * rgpBookmarks[],
342                                   DBHASHVALUE rgHashedValues[], DBROWSTATUS rgBookmarkStatus[])
343 {
344     server *This = impl_from_IWineRowServer(iface);
345     FIXME("(%p): stub\n", This);
346     return E_NOTIMPL;
347 }
348
349 static HRESULT WINAPI server_GetProperties(IWineRowServer* iface, ULONG cPropertyIDSets,
350                                            const DBPROPIDSET *rgPropertyIDSets, ULONG *pcPropertySets,
351                                            DBPROPSET **prgPropertySets)
352 {
353     server *This = impl_from_IWineRowServer(iface);
354     IRowsetInfo *rowsetinfo;
355     HRESULT hr;
356
357     TRACE("(%p)->(%d, %p, %p, %p)\n", This, cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
358
359     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowsetInfo, (void**)&rowsetinfo);
360     if(FAILED(hr)) return hr;
361
362     hr = IRowsetInfo_GetProperties(rowsetinfo, cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
363     IRowsetInfo_Release(rowsetinfo);
364
365     TRACE("returning %08x\n", hr);
366     return hr;
367 }
368
369 static HRESULT WINAPI server_GetReferencedRowset(IWineRowServer* iface, DBORDINAL iOrdinal,
370                                                  REFIID riid, IUnknown **ppReferencedRowset)
371 {
372     server *This = impl_from_IWineRowServer(iface);
373     FIXME("(%p): stub\n", This);
374     return E_NOTIMPL;
375 }
376
377 static HRESULT WINAPI server_GetSpecification(IWineRowServer* iface, REFIID riid,
378                                                IUnknown **ppSpecification)
379 {
380     server *This = impl_from_IWineRowServer(iface);
381     FIXME("(%p): stub\n", This);
382     return E_NOTIMPL;
383 }
384
385 static HRESULT WINAPI server_AddRefAccessor(IWineRowServer* iface, HACCESSOR hAccessor,
386                                             DBREFCOUNT *pcRefCount)
387 {
388     server *This = impl_from_IWineRowServer(iface);
389     FIXME("(%p): stub\n", This);
390     return E_NOTIMPL;
391 }
392
393 static HRESULT WINAPI server_CreateAccessor(IWineRowServer* iface, DBACCESSORFLAGS dwAccessorFlags,
394                                             DBCOUNTITEM cBindings, const DBBINDING *rgBindings, DBLENGTH cbRowSize,
395                                             HACCESSOR *phAccessor, DBBINDSTATUS *rgStatus)
396 {
397     server *This = impl_from_IWineRowServer(iface);
398     HRESULT hr;
399     IAccessor *accessor;
400
401     TRACE("(%p)->(%08x, %d, %p, %d, %p, %p)\n", This, dwAccessorFlags, cBindings, rgBindings, cbRowSize, phAccessor, rgStatus);
402
403     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IAccessor, (void**)&accessor);
404     if(FAILED(hr)) return hr;
405
406     hr = IAccessor_CreateAccessor(accessor, dwAccessorFlags, cBindings, rgBindings, cbRowSize, phAccessor, rgStatus);
407     IAccessor_Release(accessor);
408
409     TRACE("returning %08x, accessor %08lx\n", hr, *phAccessor);
410     return hr;
411 }
412
413 static HRESULT WINAPI server_GetBindings(IWineRowServer* iface, HACCESSOR hAccessor,
414                                          DBACCESSORFLAGS *pdwAccessorFlags, DBCOUNTITEM *pcBindings,
415                                          DBBINDING **prgBindings)
416 {
417     server *This = impl_from_IWineRowServer(iface);
418     HRESULT hr;
419     IAccessor *accessor;
420
421     TRACE("(%p)->(%08lx, %p, %p, %p)\n", This, hAccessor, pdwAccessorFlags, pcBindings, prgBindings);
422
423     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IAccessor, (void**)&accessor);
424     if(FAILED(hr)) return hr;
425
426     hr = IAccessor_GetBindings(accessor, hAccessor, pdwAccessorFlags, pcBindings, prgBindings);
427     IAccessor_Release(accessor);
428
429     TRACE("returning %08x\n", hr);
430     return hr;
431 }
432
433 static HRESULT WINAPI server_ReleaseAccessor(IWineRowServer* iface, HACCESSOR hAccessor,
434                                              DBREFCOUNT *pcRefCount)
435 {
436     server *This = impl_from_IWineRowServer(iface);
437     HRESULT hr;
438     IAccessor *accessor;
439
440     TRACE("(%p)->(%08lx, %p)\n", This, hAccessor, pcRefCount);
441
442     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IAccessor, (void**)&accessor);
443     if(FAILED(hr)) return hr;
444
445     hr = IAccessor_ReleaseAccessor(accessor, hAccessor, pcRefCount);
446     IAccessor_Release(accessor);
447
448     return hr;
449 }
450
451 static const IWineRowServerVtbl server_vtbl =
452 {
453     server_QueryInterface,
454     server_AddRef,
455     server_Release,
456     server_SetInnerUnk,
457     server_GetMarshal,
458     server_GetColumns,
459     server_GetSourceRowset,
460     server_Open,
461     server_SetColumns,
462     server_AddRefRows,
463     server_GetData,
464     server_GetNextRows,
465     server_ReleaseRows,
466     server_RestartPosition,
467     server_Compare,
468     server_GetRowsAt,
469     server_GetRowsByBookmark,
470     server_Hash,
471     server_GetProperties,
472     server_GetReferencedRowset,
473     server_GetSpecification,
474     server_AddRefAccessor,
475     server_CreateAccessor,
476     server_GetBindings,
477     server_ReleaseAccessor
478 };
479
480 static HRESULT create_server(IUnknown *outer, const CLSID *class, void **obj)
481 {
482     server *server;
483     TRACE("(%p, %s, %p)\n", outer, debugstr_guid(class), obj);
484
485     *obj = NULL;
486
487     server = HeapAlloc(GetProcessHeap(), 0, sizeof(*server));
488     if(!server) return E_OUTOFMEMORY;
489
490     server->vtbl = &server_vtbl;
491     server->ref = 1;
492     server->class = *class;
493     server->inner_unk = NULL;
494     if(IsEqualGUID(class, &CLSID_wine_row_server))
495         create_row_marshal((IUnknown*)server, (void**)&server->marshal);
496     else if(IsEqualGUID(class, &CLSID_wine_rowset_server))
497         create_rowset_marshal((IUnknown*)server, (void**)&server->marshal);
498     else
499         ERR("create_server called with class %s\n", debugstr_guid(class));
500
501     *obj = server;
502     return S_OK;
503 }
504
505 HRESULT create_row_server(IUnknown *outer, void **obj)
506 {
507     return create_server(outer, &CLSID_wine_row_server, obj);
508 }
509
510 HRESULT create_rowset_server(IUnknown *outer, void **obj)
511 {
512     return create_server(outer, &CLSID_wine_rowset_server, obj);
513 }
514
515 typedef struct
516 {
517     const IRowVtbl *row_vtbl;
518     const IRowChangeVtbl *row_change_vtbl;
519
520     LONG ref;
521
522     IWineRowServer *server;
523 } row_proxy;
524
525 static inline row_proxy *impl_from_IRow(IRow *iface)
526 {
527     return (row_proxy *)((char*)iface - FIELD_OFFSET(row_proxy, row_vtbl));
528 }
529
530 static inline row_proxy *impl_from_IRowChange(IRowChange *iface)
531 {
532     return (row_proxy *)((char*)iface - FIELD_OFFSET(row_proxy, row_change_vtbl));
533 }
534
535 static HRESULT WINAPI row_QueryInterface(IRow *iface, REFIID iid, void **obj)
536 {
537     row_proxy *This = impl_from_IRow(iface);
538     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(iid), obj);
539
540     if(IsEqualIID(iid, &IID_IUnknown) ||
541        IsEqualIID(iid, &IID_IRow))
542     {
543         *obj = &This->row_vtbl;
544     }
545     else if(IsEqualIID(iid, &IID_IRowChange))
546     {
547         *obj = &This->row_change_vtbl;
548     }
549     else
550     {
551         FIXME("interface %s not implemented\n", debugstr_guid(iid));
552         return E_NOINTERFACE;
553     }
554
555     IRow_AddRef(iface);
556     return S_OK;
557 }
558
559 static ULONG WINAPI row_AddRef(IRow *iface)
560 {
561     row_proxy *This = impl_from_IRow(iface);
562     TRACE("(%p)\n", This);
563
564     return InterlockedIncrement(&This->ref);
565 }
566
567 static ULONG WINAPI row_Release(IRow *iface)
568 {
569     row_proxy *This = impl_from_IRow(iface);
570     LONG ref;
571
572     TRACE("(%p)\n", This);
573
574     ref = InterlockedDecrement(&This->ref);
575     if(ref == 0)
576     {
577         if(This->server) IWineRowServer_Release(This->server);
578         HeapFree(GetProcessHeap(), 0, This);
579     }
580
581     return ref;
582 }
583
584 static HRESULT WINAPI row_GetColumns(IRow* iface, DBORDINAL cColumns, DBCOLUMNACCESS rgColumns[])
585 {
586     row_proxy *This = impl_from_IRow(iface);
587     DBORDINAL i;
588     wine_getcolumns_in *in_data;
589     wine_getcolumns_out *out_data;
590     HRESULT hr;
591
592     TRACE("(%p)->(%d, %p)\n", This, cColumns, rgColumns);
593
594     in_data = CoTaskMemAlloc(cColumns * sizeof(in_data[0]));
595     out_data = CoTaskMemAlloc(cColumns * sizeof(out_data[0]));
596
597     for(i = 0; i < cColumns; i++)
598     {
599         TRACE("%d:\tdata %p data_len %d status %08x max_len %d type %04x\n", i, rgColumns[i].pData,
600               rgColumns[i].cbDataLen, rgColumns[i].dwStatus, rgColumns[i].cbMaxLen, rgColumns[i].wType);
601         in_data[i].columnid     = rgColumns[i].columnid;
602         in_data[i].max_len      = rgColumns[i].cbMaxLen;
603         in_data[i].type         = rgColumns[i].wType;
604         in_data[i].precision    = rgColumns[i].bPrecision;
605         in_data[i].scale        = rgColumns[i].bScale;
606     }
607
608     hr = IWineRowServer_GetColumns(This->server, cColumns, in_data, out_data);
609
610     for(i = 0; i < cColumns; i++)
611     {
612         rgColumns[i].cbDataLen = out_data[i].data_len;
613         rgColumns[i].dwStatus  = out_data[i].status;
614         if(rgColumns[i].dwStatus == DBSTATUS_S_OK)
615             memcpy(rgColumns[i].pData, &V_I1(&out_data[i].v), out_data[i].data_len);
616     }
617
618     CoTaskMemFree(out_data);
619     CoTaskMemFree(in_data);
620     return hr;
621 }
622
623 static HRESULT WINAPI row_GetSourceRowset(IRow* iface, REFIID riid, IUnknown **ppRowset,
624                                           HROW *phRow)
625 {
626     row_proxy *This = impl_from_IRow(iface);
627
628     FIXME("(%p)->(%s, %p, %p): stub\n", This, debugstr_guid(riid), ppRowset, phRow);
629
630     return E_NOTIMPL;
631 }
632
633 static HRESULT WINAPI row_Open(IRow* iface, IUnknown *pUnkOuter,
634                                DBID *pColumnID, REFGUID rguidColumnType,
635                                DWORD dwBindFlags, REFIID riid, IUnknown **ppUnk)
636 {
637     row_proxy *This = impl_from_IRow(iface);
638
639     FIXME("(%p)->(%p, %p, %s, %08x, %s, %p): stub\n", This, pUnkOuter, pColumnID, debugstr_guid(rguidColumnType),
640           dwBindFlags, debugstr_guid(riid), ppUnk);
641
642     return E_NOTIMPL;
643 }
644
645 static const IRowVtbl row_vtbl =
646 {
647     row_QueryInterface,
648     row_AddRef,
649     row_Release,
650     row_GetColumns,
651     row_GetSourceRowset,
652     row_Open
653 };
654
655 static HRESULT WINAPI row_change_QueryInterface(IRowChange *iface, REFIID iid, void **obj)
656 {
657     row_proxy *This = impl_from_IRowChange(iface);
658     return IUnknown_QueryInterface((IUnknown *)This, iid, obj);
659 }
660
661 static ULONG WINAPI row_change_AddRef(IRowChange *iface)
662 {
663     row_proxy *This = impl_from_IRowChange(iface);
664     return IUnknown_AddRef((IUnknown*)This);
665 }
666
667 static ULONG WINAPI row_change_Release(IRowChange *iface)
668 {
669     row_proxy *This = impl_from_IRowChange(iface);
670     return IUnknown_Release((IUnknown*)This);
671 }
672
673 static HRESULT WINAPI row_change_SetColumns(IRowChange *iface, DBORDINAL cColumns,
674                                             DBCOLUMNACCESS rgColumns[])
675 {
676     row_proxy *This = impl_from_IRowChange(iface);
677     FIXME("(%p)->(%d, %p)\n", This, cColumns, rgColumns);
678     return E_NOTIMPL;
679 }
680
681 static const IRowChangeVtbl row_change_vtbl =
682 {
683     row_change_QueryInterface,
684     row_change_AddRef,
685     row_change_Release,
686     row_change_SetColumns
687 };
688
689 static HRESULT create_row_proxy(IWineRowServer *server, IUnknown **obj)
690 {
691     row_proxy *proxy;
692
693     TRACE("(%p, %p)\n", server, obj);
694     *obj = NULL;
695
696     proxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*proxy));
697     if(!proxy) return E_OUTOFMEMORY;
698
699     proxy->row_vtbl = &row_vtbl;
700     proxy->row_change_vtbl = &row_change_vtbl;
701     proxy->ref = 1;
702     IWineRowServer_AddRef(server);
703     proxy->server = server;
704
705     *obj = (IUnknown*)&proxy->row_vtbl;
706     TRACE("returing %p\n", *obj);
707     return S_OK;
708 }
709
710 typedef struct
711 {
712     const IRowsetVtbl *rowset_vtbl;
713     const IRowsetLocateVtbl *rowsetlocate_vtbl;
714     const IRowsetInfoVtbl *rowsetinfo_vtbl;
715     const IAccessorVtbl *accessor_vtbl;
716
717     LONG ref;
718
719     IWineRowServer *server;
720 } rowset_proxy;
721
722 static inline rowset_proxy *impl_from_IRowset(IRowset *iface)
723 {
724     return (rowset_proxy *)((char*)iface - FIELD_OFFSET(rowset_proxy, rowset_vtbl));
725 }
726
727 static inline rowset_proxy *impl_from_IRowsetLocate(IRowsetLocate *iface)
728 {
729     return (rowset_proxy *)((char*)iface - FIELD_OFFSET(rowset_proxy, rowsetlocate_vtbl));
730 }
731
732 static inline rowset_proxy *impl_from_IRowsetInfo(IRowsetInfo *iface)
733 {
734     return (rowset_proxy *)((char*)iface - FIELD_OFFSET(rowset_proxy, rowsetinfo_vtbl));
735 }
736
737 static inline rowset_proxy *impl_from_IAccessor(IAccessor *iface)
738 {
739     return (rowset_proxy *)((char*)iface - FIELD_OFFSET(rowset_proxy, accessor_vtbl));
740 }
741
742 static HRESULT WINAPI rowset_QueryInterface(IRowset *iface, REFIID iid, void **obj)
743 {
744     rowset_proxy *This = impl_from_IRowset(iface);
745     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(iid), obj);
746
747     *obj = NULL;
748
749     if(IsEqualIID(iid, &IID_IUnknown) ||
750        IsEqualIID(iid, &IID_IRowset))
751     {
752         *obj = &This->rowset_vtbl;
753     }
754     else if(IsEqualIID(iid, &IID_IRowsetLocate))
755     {
756         *obj = &This->rowsetlocate_vtbl;
757     }
758     else if(IsEqualIID(iid, &IID_IRowsetInfo))
759     {
760         *obj = &This->rowsetinfo_vtbl;
761     }
762     else if(IsEqualIID(iid, &IID_IAccessor))
763     {
764         *obj = &This->accessor_vtbl;
765     }
766     else
767     {
768         FIXME("interface %s not implemented\n", debugstr_guid(iid));
769         return E_NOINTERFACE;
770     }
771
772     IRowset_AddRef(iface);
773     return S_OK;
774 }
775
776 static ULONG WINAPI rowset_AddRef(IRowset *iface)
777 {
778     rowset_proxy *This = impl_from_IRowset(iface);
779     TRACE("(%p)\n", This);
780
781     return InterlockedIncrement(&This->ref);
782 }
783
784 static ULONG WINAPI rowset_Release(IRowset *iface)
785 {
786     rowset_proxy *This = impl_from_IRowset(iface);
787     LONG ref;
788
789     TRACE("(%p)\n", This);
790
791     ref = InterlockedDecrement(&This->ref);
792     if(ref == 0)
793     {
794         if(This->server) IWineRowServer_Release(This->server);
795         HeapFree(GetProcessHeap(), 0, This);
796     }
797
798     return ref;
799 }
800
801 static HRESULT WINAPI rowset_AddRefRows(IRowset *iface, DBCOUNTITEM cRows, const HROW rghRows[],
802                                         DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[])
803 {
804     rowset_proxy *This = impl_from_IRowset(iface);
805     HRESULT hr;
806     DBREFCOUNT *refs = rgRefCounts;
807     DBSTATUS *stats = rgRowStatus;
808
809     TRACE("(%p)->(%d, %p, %p, %p)\n", This, cRows, rghRows, rgRefCounts, rgRowStatus);
810
811     if(!refs) refs = CoTaskMemAlloc(cRows * sizeof(refs[0]));
812     if(!stats) stats = CoTaskMemAlloc(cRows * sizeof(stats[0]));
813
814     hr = IWineRowServer_AddRefRows(This->server, cRows, rghRows, refs, stats);
815
816     if(refs != rgRefCounts) CoTaskMemFree(refs);
817     if(stats != rgRowStatus) CoTaskMemFree(stats);
818
819     return hr;
820 }
821
822 static HRESULT WINAPI rowset_GetData(IRowset *iface, HROW hRow, HACCESSOR hAccessor, void *pData)
823 {
824     rowset_proxy *This = impl_from_IRowset(iface);
825
826     FIXME("(%p)->(%lx, %lx, %p): stub\n", This, hRow, hAccessor, pData);
827
828     return E_NOTIMPL;
829 }
830
831 static HRESULT WINAPI rowset_GetNextRows(IRowset *iface, HCHAPTER hReserved, DBROWOFFSET lRowsOffset,
832                                          DBROWCOUNT cRows, DBCOUNTITEM *pcRowObtained, HROW **prghRows)
833 {
834     rowset_proxy *This = impl_from_IRowset(iface);
835     HRESULT hr;
836     HROW *rows = NULL;
837
838     TRACE("(%p)->(%08lx, %d, %d, %p, %p)\n", This, hReserved, lRowsOffset, cRows, pcRowObtained, prghRows);
839
840     hr = IWineRowServer_GetNextRows(This->server, hReserved, lRowsOffset, cRows, pcRowObtained, &rows);
841     if(*prghRows)
842     {
843         memcpy(*prghRows, rows, *pcRowObtained * sizeof(rows[0]));
844         CoTaskMemFree(rows);
845     }
846     else
847         *prghRows = rows;
848
849     return hr;
850 }
851
852 static HRESULT WINAPI rowset_ReleaseRows(IRowset *iface, DBCOUNTITEM cRows, const HROW rghRows[],
853                                          DBROWOPTIONS rgRowOptions[], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[])
854 {
855     rowset_proxy *This = impl_from_IRowset(iface);
856     HRESULT hr;
857     DBROWOPTIONS *options = rgRowOptions;
858     DBREFCOUNT *refs = rgRefCounts;
859     DBROWSTATUS *status = rgRowStatus;
860
861     TRACE("(%p)->(%d, %p, %p, %p, %p)\n", This, cRows, rghRows, rgRowOptions, rgRefCounts, rgRowStatus);
862
863     if(!options)
864     {
865         options = CoTaskMemAlloc(cRows * sizeof(options[0]));
866         memset(options, 0, cRows * sizeof(options[0]));
867     }
868     if(!refs) refs = CoTaskMemAlloc(cRows * sizeof(refs[0]));
869     if(!status) status = CoTaskMemAlloc(cRows * sizeof(status[0]));
870
871     hr = IWineRowServer_ReleaseRows(This->server, cRows, rghRows, options, refs, status);
872
873     if(status != rgRowStatus) CoTaskMemFree(status);
874     if(refs != rgRefCounts) CoTaskMemFree(refs);
875     if(options != rgRowOptions) CoTaskMemFree(options);
876
877     return hr;
878 }
879
880 static HRESULT WINAPI rowset_RestartPosition(IRowset* iface, HCHAPTER hReserved)
881 {
882     rowset_proxy *This = impl_from_IRowset(iface);
883
884     FIXME("(%p)->(%lx): stub\n", This, hReserved);
885
886     return E_NOTIMPL;
887 }
888
889 static const IRowsetVtbl rowset_vtbl =
890 {
891     rowset_QueryInterface,
892     rowset_AddRef,
893     rowset_Release,
894     rowset_AddRefRows,
895     rowset_GetData,
896     rowset_GetNextRows,
897     rowset_ReleaseRows,
898     rowset_RestartPosition
899 };
900
901 static HRESULT WINAPI rowsetlocate_QueryInterface(IRowsetLocate *iface, REFIID iid, void **obj)
902 {
903     rowset_proxy *This = impl_from_IRowsetLocate(iface);
904     return IUnknown_QueryInterface((IUnknown *)This, iid, obj);
905 }
906
907 static ULONG WINAPI rowsetlocate_AddRef(IRowsetLocate *iface)
908 {
909     rowset_proxy *This = impl_from_IRowsetLocate(iface);
910     return IUnknown_AddRef((IUnknown *)This);
911 }
912
913 static ULONG WINAPI rowsetlocate_Release(IRowsetLocate *iface)
914 {
915     rowset_proxy *This = impl_from_IRowsetLocate(iface);
916     return IUnknown_Release((IUnknown *)This);
917 }
918
919 static HRESULT WINAPI rowsetlocate_AddRefRows(IRowsetLocate *iface, DBCOUNTITEM cRows, const HROW rghRows[],
920                                               DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[])
921 {
922     rowset_proxy *This = impl_from_IRowsetLocate(iface);
923     return IRowset_AddRefRows((IRowset*)This, cRows, rghRows, rgRefCounts, rgRowStatus);
924 }
925
926 static HRESULT WINAPI rowsetlocate_GetData(IRowsetLocate *iface, HROW hRow, HACCESSOR hAccessor, void *pData)
927 {
928     rowset_proxy *This = impl_from_IRowsetLocate(iface);
929     return IRowset_GetData((IRowset*)This, hRow, hAccessor, pData);
930 }
931
932 static HRESULT WINAPI rowsetlocate_GetNextRows(IRowsetLocate *iface, HCHAPTER hReserved, DBROWOFFSET lRowsOffset,
933                                                DBROWCOUNT cRows, DBCOUNTITEM *pcRowObtained, HROW **prghRows)
934 {
935     rowset_proxy *This = impl_from_IRowsetLocate(iface);
936     return IRowset_GetNextRows((IRowset*)This, hReserved, lRowsOffset, cRows, pcRowObtained, prghRows);
937 }
938
939 static HRESULT WINAPI rowsetlocate_ReleaseRows(IRowsetLocate *iface, DBCOUNTITEM cRows, const HROW rghRows[],
940                                                DBROWOPTIONS rgRowOptions[], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[])
941 {
942     rowset_proxy *This = impl_from_IRowsetLocate(iface);
943     return IRowset_ReleaseRows((IRowset*)This, cRows, rghRows, rgRowOptions, rgRefCounts, rgRowStatus);
944 }
945
946 static HRESULT WINAPI rowsetlocate_RestartPosition(IRowsetLocate *iface, HCHAPTER hReserved)
947 {
948     rowset_proxy *This = impl_from_IRowsetLocate(iface);
949     return IRowset_RestartPosition((IRowset*)This, hReserved);
950 }
951
952 static HRESULT WINAPI rowsetlocate_Compare(IRowsetLocate *iface, HCHAPTER hReserved, DBBKMARK cbBookmark1, const BYTE *pBookmark1,
953                                            DBBKMARK cbBookmark2, const BYTE *pBookmark2, DBCOMPARE *pComparison)
954 {
955     rowset_proxy *This = impl_from_IRowsetLocate(iface);
956     FIXME("(%p)\n", This);
957     return E_NOTIMPL;
958 }
959
960 static HRESULT WINAPI rowsetlocate_GetRowsAt(IRowsetLocate *iface, HWATCHREGION hReserved1, HCHAPTER hReserved2, DBBKMARK cbBookmark,
961                                              const BYTE *pBookmark, DBROWOFFSET lRowsOffset, DBROWCOUNT cRows, DBCOUNTITEM *pcRowsObtained,
962                                              HROW **prghRows)
963 {
964     rowset_proxy *This = impl_from_IRowsetLocate(iface);
965     FIXME("(%p)\n", This);
966     return E_NOTIMPL;
967 }
968
969 static HRESULT WINAPI rowsetlocate_GetRowsByBookmark(IRowsetLocate *iface, HCHAPTER hReserved, DBCOUNTITEM cRows, const DBBKMARK rgcbBookmarks[],
970                                                      const BYTE * rgpBookmarks[], HROW rghRows[], DBROWSTATUS rgRowStatus[])
971 {
972     rowset_proxy *This = impl_from_IRowsetLocate(iface);
973     FIXME("(%p)\n", This);
974     return E_NOTIMPL;
975 }
976
977 static HRESULT WINAPI rowsetlocate_Hash(IRowsetLocate *iface, HCHAPTER hReserved, DBBKMARK cBookmarks, const DBBKMARK rgcbBookmarks[],
978                                         const BYTE * rgpBookmarks[], DBHASHVALUE rgHashedValues[], DBROWSTATUS rgBookmarkStatus[])
979 {
980     rowset_proxy *This = impl_from_IRowsetLocate(iface);
981     FIXME("(%p)\n", This);
982     return E_NOTIMPL;
983 }
984
985 static const IRowsetLocateVtbl rowsetlocate_vtbl =
986 {
987     rowsetlocate_QueryInterface,
988     rowsetlocate_AddRef,
989     rowsetlocate_Release,
990     rowsetlocate_AddRefRows,
991     rowsetlocate_GetData,
992     rowsetlocate_GetNextRows,
993     rowsetlocate_ReleaseRows,
994     rowsetlocate_RestartPosition,
995     rowsetlocate_Compare,
996     rowsetlocate_GetRowsAt,
997     rowsetlocate_GetRowsByBookmark,
998     rowsetlocate_Hash
999 };
1000
1001 static HRESULT WINAPI rowsetinfo_QueryInterface(IRowsetInfo *iface, REFIID iid, void **obj)
1002 {
1003     rowset_proxy *This = impl_from_IRowsetInfo(iface);
1004     return IUnknown_QueryInterface((IUnknown *)This, iid, obj);
1005 }
1006
1007 static ULONG WINAPI rowsetinfo_AddRef(IRowsetInfo *iface)
1008 {
1009     rowset_proxy *This = impl_from_IRowsetInfo(iface);
1010     return IUnknown_AddRef((IUnknown *)This);
1011 }
1012
1013 static ULONG WINAPI rowsetinfo_Release(IRowsetInfo *iface)
1014 {
1015     rowset_proxy *This = impl_from_IRowsetInfo(iface);
1016     return IUnknown_Release((IUnknown *)This);
1017 }
1018
1019 static HRESULT WINAPI rowsetinfo_GetProperties(IRowsetInfo *iface, const ULONG cPropertyIDSets,
1020                                                const DBPROPIDSET rgPropertyIDSets[], ULONG *pcPropertySets,
1021                                                DBPROPSET **prgPropertySets)
1022 {
1023     rowset_proxy *This = impl_from_IRowsetInfo(iface);
1024     HRESULT hr;
1025
1026     TRACE("(%p)->(%d, %p, %p, %p)\n", This, cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
1027
1028     hr = IWineRowServer_GetProperties(This->server, cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
1029
1030     return hr;
1031 }
1032
1033 static HRESULT WINAPI rowsetinfo_GetReferencedRowset(IRowsetInfo *iface, DBORDINAL iOrdinal, REFIID riid,
1034                                                      IUnknown **ppReferencedRowset)
1035 {
1036     rowset_proxy *This = impl_from_IRowsetInfo(iface);
1037     FIXME("(%p)\n", This);
1038     return E_NOTIMPL;
1039 }
1040
1041 static HRESULT WINAPI rowsetinfo_GetSpecification(IRowsetInfo *iface, REFIID riid, IUnknown **ppSpecification)
1042 {
1043     rowset_proxy *This = impl_from_IRowsetInfo(iface);
1044     FIXME("(%p)\n", This);
1045     return E_NOTIMPL;
1046 }
1047
1048 static const IRowsetInfoVtbl rowsetinfo_vtbl =
1049 {
1050     rowsetinfo_QueryInterface,
1051     rowsetinfo_AddRef,
1052     rowsetinfo_Release,
1053     rowsetinfo_GetProperties,
1054     rowsetinfo_GetReferencedRowset,
1055     rowsetinfo_GetSpecification
1056 };
1057
1058 static HRESULT WINAPI accessor_QueryInterface(IAccessor *iface, REFIID iid, void **obj)
1059 {
1060     rowset_proxy *This = impl_from_IAccessor(iface);
1061     return IUnknown_QueryInterface((IUnknown *)This, iid, obj);
1062 }
1063
1064 static ULONG WINAPI accessor_AddRef(IAccessor *iface)
1065 {
1066     rowset_proxy *This = impl_from_IAccessor(iface);
1067     return IUnknown_AddRef((IUnknown *)This);
1068 }
1069
1070 static ULONG WINAPI accessor_Release(IAccessor *iface)
1071 {
1072     rowset_proxy *This = impl_from_IAccessor(iface);
1073     return IUnknown_Release((IUnknown *)This);
1074 }
1075
1076 static HRESULT WINAPI accessor_AddRefAccessor(IAccessor *iface, HACCESSOR hAccessor, DBREFCOUNT *pcRefCount)
1077 {
1078     rowset_proxy *This = impl_from_IAccessor(iface);
1079     FIXME("(%p)\n", This);
1080     return E_NOTIMPL;
1081 }
1082
1083 static HRESULT WINAPI accessor_CreateAccessor(IAccessor *iface, DBACCESSORFLAGS dwAccessorFlags, DBCOUNTITEM cBindings,
1084                                               const DBBINDING rgBindings[], DBLENGTH cbRowSize, HACCESSOR *phAccessor,
1085                                               DBBINDSTATUS rgStatus[])
1086 {
1087     rowset_proxy *This = impl_from_IAccessor(iface);
1088     HRESULT hr;
1089     DBBINDSTATUS *status;
1090
1091     TRACE("(%p)->(%08x, %d, %p, %d, %p, %p)\n", This, dwAccessorFlags, cBindings, rgBindings, cbRowSize, phAccessor, rgStatus);
1092
1093     if(!rgStatus) status = CoTaskMemAlloc(cBindings * sizeof(status[0]));
1094     else status = rgStatus;
1095
1096     hr = IWineRowServer_CreateAccessor(This->server, dwAccessorFlags, cBindings, rgBindings, cbRowSize, phAccessor, status);
1097
1098     if(!rgStatus) CoTaskMemFree(status);
1099
1100     return hr;
1101 }
1102
1103 static HRESULT WINAPI accessor_GetBindings(IAccessor *iface, HACCESSOR hAccessor, DBACCESSORFLAGS *pdwAccessorFlags,
1104                                            DBCOUNTITEM *pcBindings, DBBINDING **prgBindings)
1105 {
1106     rowset_proxy *This = impl_from_IAccessor(iface);
1107     HRESULT hr;
1108
1109     TRACE("(%p)->(%08lx, %p, %p, %p)\n", This, hAccessor, pdwAccessorFlags, pcBindings, prgBindings);
1110
1111     hr = IWineRowServer_GetBindings(This->server, hAccessor, pdwAccessorFlags, pcBindings, prgBindings);
1112
1113     return hr;
1114 }
1115
1116 static HRESULT WINAPI accessor_ReleaseAccessor(IAccessor *iface, HACCESSOR hAccessor, DBREFCOUNT *pcRefCount)
1117 {
1118     rowset_proxy *This = impl_from_IAccessor(iface);
1119     HRESULT hr;
1120     DBREFCOUNT ref;
1121
1122     TRACE("(%p)->(%08lx, %p)\n", This, hAccessor, pcRefCount);
1123
1124     hr = IWineRowServer_ReleaseAccessor(This->server, hAccessor, &ref);
1125     if(pcRefCount) *pcRefCount = ref;
1126     return hr;
1127 }
1128
1129 static const IAccessorVtbl accessor_vtbl =
1130 {
1131     accessor_QueryInterface,
1132     accessor_AddRef,
1133     accessor_Release,
1134     accessor_AddRefAccessor,
1135     accessor_CreateAccessor,
1136     accessor_GetBindings,
1137     accessor_ReleaseAccessor
1138 };
1139
1140 HRESULT create_rowset_proxy(IWineRowServer *server, IUnknown **obj)
1141 {
1142     rowset_proxy *proxy;
1143
1144     TRACE("(%p, %p)\n", server, obj);
1145     *obj = NULL;
1146
1147     proxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*proxy));
1148     if(!proxy) return E_OUTOFMEMORY;
1149
1150     proxy->rowset_vtbl = &rowset_vtbl;
1151     proxy->rowsetlocate_vtbl = &rowsetlocate_vtbl;
1152     proxy->rowsetinfo_vtbl = &rowsetinfo_vtbl;
1153     proxy->accessor_vtbl = &accessor_vtbl;
1154     proxy->ref = 1;
1155     IWineRowServer_AddRef(server);
1156     proxy->server = server;
1157
1158     *obj = (IUnknown *)&proxy->rowset_vtbl;
1159     TRACE("returing %p\n", *obj);
1160     return S_OK;
1161 }
1162
1163 static HRESULT create_proxy(IWineRowServer *server, const CLSID *class, IUnknown **obj)
1164 {
1165     *obj = NULL;
1166
1167     if(IsEqualGUID(class, &CLSID_wine_row_proxy))
1168         return create_row_proxy(server, obj);
1169     else if(IsEqualGUID(class, &CLSID_wine_rowset_proxy))
1170         return create_rowset_proxy(server, obj);
1171     else
1172         FIXME("Unhandled proxy class %s\n", debugstr_guid(class));
1173     return E_NOTIMPL;
1174 }
1175
1176 /* Marshal impl */
1177
1178 typedef struct
1179 {
1180     const IMarshalVtbl *marshal_vtbl;
1181
1182     LONG ref;
1183     CLSID unmarshal_class;
1184     IUnknown *outer;
1185 } marshal;
1186
1187 static inline marshal *impl_from_IMarshal(IMarshal *iface)
1188 {
1189     return (marshal *)((char*)iface - FIELD_OFFSET(marshal, marshal_vtbl));
1190 }
1191
1192 static HRESULT WINAPI marshal_QueryInterface(IMarshal *iface, REFIID iid, void **obj)
1193 {
1194     marshal *This = impl_from_IMarshal(iface);
1195     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(iid), obj);
1196
1197     if(IsEqualIID(iid, &IID_IUnknown) ||
1198        IsEqualIID(iid, &IID_IMarshal))
1199     {
1200         *obj = iface;
1201     }
1202     else
1203     {
1204         FIXME("interface %s not implemented\n", debugstr_guid(iid));
1205         *obj = NULL;
1206         return E_NOINTERFACE;
1207     }
1208
1209     IMarshal_AddRef(iface);
1210     return S_OK;
1211 }
1212
1213 static ULONG WINAPI marshal_AddRef(IMarshal *iface)
1214 {
1215     marshal *This = impl_from_IMarshal(iface);
1216     TRACE("(%p)\n", This);
1217     return InterlockedIncrement(&This->ref);
1218 }
1219
1220 static ULONG WINAPI marshal_Release(IMarshal *iface)
1221 {
1222     marshal *This = impl_from_IMarshal(iface);
1223     LONG ref;
1224
1225     TRACE("(%p)\n", This);
1226
1227     ref = InterlockedDecrement(&This->ref);
1228     if(ref == 0)
1229     {
1230         HeapFree(GetProcessHeap(), 0, This);
1231     }
1232
1233     return ref;
1234 }
1235
1236 static HRESULT WINAPI marshal_GetUnmarshalClass(IMarshal *iface, REFIID iid, void *obj,
1237                                                 DWORD dwDestContext, void *pvDestContext,
1238                                                 DWORD mshlflags, CLSID *clsid)
1239 {
1240     marshal *This = impl_from_IMarshal(iface);
1241     TRACE("(%p)->(%s, %p, %08x, %p, %08x, %p)\n", This, debugstr_guid(iid), obj, dwDestContext,
1242           pvDestContext, mshlflags, clsid);
1243
1244     *clsid = This->unmarshal_class;
1245     return S_OK;
1246 }
1247
1248 static HRESULT WINAPI marshal_GetMarshalSizeMax(IMarshal *iface, REFIID iid, void *obj,
1249                                                 DWORD dwDestContext, void *pvDestContext,
1250                                                 DWORD mshlflags, DWORD *size)
1251 {
1252     marshal *This = impl_from_IMarshal(iface);
1253     TRACE("(%p)->(%s, %p, %08x, %p, %08x, %p)\n", This, debugstr_guid(iid), obj, dwDestContext,
1254           pvDestContext, mshlflags, size);
1255
1256     return CoGetMarshalSizeMax(size, &IID_IWineRowServer, This->outer, dwDestContext, pvDestContext,
1257                                mshlflags);
1258 }
1259
1260 static HRESULT WINAPI marshal_MarshalInterface(IMarshal *iface, IStream *stream, REFIID iid,
1261                                                void *obj, DWORD dwDestContext, void *pvDestContext,
1262                                                DWORD mshlflags)
1263 {
1264     marshal *This = impl_from_IMarshal(iface);
1265     TRACE("(%p)->(%p, %s, %p, %08x, %p, %08x)\n", This, stream, debugstr_guid(iid), obj, dwDestContext,
1266           pvDestContext, mshlflags);
1267
1268     return CoMarshalInterface(stream, &IID_IWineRowServer, This->outer, dwDestContext, pvDestContext, mshlflags);
1269 }
1270
1271 static HRESULT WINAPI marshal_UnmarshalInterface(IMarshal *iface, IStream *stream,
1272                                                  REFIID iid, void **obj)
1273 {
1274     marshal *This = impl_from_IMarshal(iface);
1275     HRESULT hr;
1276     IWineRowServer *server;
1277     IUnknown *proxy;
1278
1279     TRACE("(%p)->(%p, %s, %p)\n", This, stream, debugstr_guid(iid), obj);
1280     *obj = NULL;
1281
1282     hr = CoUnmarshalInterface(stream, &IID_IWineRowServer, (void**)&server);
1283     if(SUCCEEDED(hr))
1284     {
1285         hr = create_proxy(server, &This->unmarshal_class, &proxy);
1286         if(SUCCEEDED(hr))
1287         {
1288             hr = IUnknown_QueryInterface(proxy, iid, obj);
1289             IUnknown_Release(proxy);
1290         }
1291         IWineRowServer_Release(server);
1292     }
1293
1294     TRACE("returing %p\n", *obj);
1295     return hr;
1296 }
1297
1298 static HRESULT WINAPI marshal_ReleaseMarshalData(IMarshal *iface, IStream *stream)
1299 {
1300     marshal *This = impl_from_IMarshal(iface);
1301     TRACE("(%p)->(%p)\n", This, stream);
1302     return CoReleaseMarshalData(stream);
1303 }
1304
1305 static HRESULT WINAPI marshal_DisconnectObject(IMarshal *iface, DWORD dwReserved)
1306 {
1307     marshal *This = impl_from_IMarshal(iface);
1308     FIXME("(%p)->(%08x)\n", This, dwReserved);
1309
1310     return E_NOTIMPL;
1311 }
1312
1313 static const IMarshalVtbl marshal_vtbl =
1314 {
1315     marshal_QueryInterface,
1316     marshal_AddRef,
1317     marshal_Release,
1318     marshal_GetUnmarshalClass,
1319     marshal_GetMarshalSizeMax,
1320     marshal_MarshalInterface,
1321     marshal_UnmarshalInterface,
1322     marshal_ReleaseMarshalData,
1323     marshal_DisconnectObject
1324 };
1325
1326 static HRESULT create_marshal(IUnknown *outer, const CLSID *class, void **obj)
1327 {
1328     marshal *marshal;
1329
1330     TRACE("(%p, %p)\n", outer, obj);
1331     *obj = NULL;
1332
1333     marshal = HeapAlloc(GetProcessHeap(), 0, sizeof(*marshal));
1334     if(!marshal) return E_OUTOFMEMORY;
1335
1336     marshal->unmarshal_class = *class;
1337     marshal->outer = outer; /* don't ref outer unk */
1338     marshal->marshal_vtbl = &marshal_vtbl;
1339     marshal->ref = 1;
1340
1341     *obj = &marshal->marshal_vtbl;
1342     TRACE("returing %p\n", *obj);
1343     return S_OK;
1344 }
1345
1346 HRESULT create_row_marshal(IUnknown *outer, void **obj)
1347 {
1348     TRACE("(%p, %p)\n", outer, obj);
1349     return create_marshal(outer, &CLSID_wine_row_proxy, obj);
1350 }
1351
1352 HRESULT create_rowset_marshal(IUnknown *outer, void **obj)
1353 {
1354     TRACE("(%p, %p)\n", outer, obj);
1355     return create_marshal(outer, &CLSID_wine_rowset_proxy, obj);
1356 }