msdaps: Add server side stubs for IAccessor.
[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     FIXME("(%p)->(%d, %p, %p, %p)\n", This, cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
355     return E_NOTIMPL;
356 }
357
358 static HRESULT WINAPI server_GetReferencedRowset(IWineRowServer* iface, DBORDINAL iOrdinal,
359                                                  REFIID riid, IUnknown **ppReferencedRowset)
360 {
361     server *This = impl_from_IWineRowServer(iface);
362     FIXME("(%p): stub\n", This);
363     return E_NOTIMPL;
364 }
365
366 static HRESULT WINAPI server_GetSpecification(IWineRowServer* iface, REFIID riid,
367                                                IUnknown **ppSpecification)
368 {
369     server *This = impl_from_IWineRowServer(iface);
370     FIXME("(%p): stub\n", This);
371     return E_NOTIMPL;
372 }
373
374 static HRESULT WINAPI server_AddRefAccessor(IWineRowServer* iface, HACCESSOR hAccessor,
375                                             DBREFCOUNT *pcRefCount)
376 {
377     server *This = impl_from_IWineRowServer(iface);
378     FIXME("(%p): stub\n", This);
379     return E_NOTIMPL;
380 }
381
382 static HRESULT WINAPI server_CreateAccessor(IWineRowServer* iface, DBACCESSORFLAGS dwAccessorFlags,
383                                             DBCOUNTITEM cBindings, const DBBINDING *rgBindings, DBLENGTH cbRowSize,
384                                             HACCESSOR *phAccessor, DBBINDSTATUS *rgStatus)
385 {
386     server *This = impl_from_IWineRowServer(iface);
387     FIXME("(%p)->(%08x, %d, %p, %d, %p, %p): stub\n", This, dwAccessorFlags, cBindings, rgBindings, cbRowSize, phAccessor, rgStatus);
388     return E_NOTIMPL;
389 }
390
391 static HRESULT WINAPI server_GetBindings(IWineRowServer* iface, HACCESSOR hAccessor,
392                                          DBACCESSORFLAGS *pdwAccessorFlags, DBCOUNTITEM *pcBindings,
393                                          DBBINDING **prgBindings)
394 {
395     server *This = impl_from_IWineRowServer(iface);
396     FIXME("(%p)->(%08lx, %p, %p, %p): stub\n", This, hAccessor, pdwAccessorFlags, pcBindings, prgBindings);
397     return E_NOTIMPL;
398 }
399
400 static HRESULT WINAPI server_ReleaseAccessor(IWineRowServer* iface, HACCESSOR hAccessor,
401                                              DBREFCOUNT *pcRefCount)
402 {
403     server *This = impl_from_IWineRowServer(iface);
404     FIXME("(%p)->(%08lx, %p): stub\n", This, hAccessor, pcRefCount);
405     return E_NOTIMPL;
406 }
407
408 static const IWineRowServerVtbl server_vtbl =
409 {
410     server_QueryInterface,
411     server_AddRef,
412     server_Release,
413     server_SetInnerUnk,
414     server_GetMarshal,
415     server_GetColumns,
416     server_GetSourceRowset,
417     server_Open,
418     server_SetColumns,
419     server_AddRefRows,
420     server_GetData,
421     server_GetNextRows,
422     server_ReleaseRows,
423     server_RestartPosition,
424     server_Compare,
425     server_GetRowsAt,
426     server_GetRowsByBookmark,
427     server_Hash,
428     server_GetProperties,
429     server_GetReferencedRowset,
430     server_GetSpecification,
431     server_AddRefAccessor,
432     server_CreateAccessor,
433     server_GetBindings,
434     server_ReleaseAccessor
435 };
436
437 static HRESULT create_server(IUnknown *outer, const CLSID *class, void **obj)
438 {
439     server *server;
440     TRACE("(%p, %s, %p)\n", outer, debugstr_guid(class), obj);
441
442     *obj = NULL;
443
444     server = HeapAlloc(GetProcessHeap(), 0, sizeof(*server));
445     if(!server) return E_OUTOFMEMORY;
446
447     server->vtbl = &server_vtbl;
448     server->ref = 1;
449     server->class = *class;
450     server->inner_unk = NULL;
451     if(IsEqualGUID(class, &CLSID_wine_row_server))
452         create_row_marshal((IUnknown*)server, (void**)&server->marshal);
453     else if(IsEqualGUID(class, &CLSID_wine_rowset_server))
454         create_rowset_marshal((IUnknown*)server, (void**)&server->marshal);
455     else
456         ERR("create_server called with class %s\n", debugstr_guid(class));
457
458     *obj = server;
459     return S_OK;
460 }
461
462 HRESULT create_row_server(IUnknown *outer, void **obj)
463 {
464     return create_server(outer, &CLSID_wine_row_server, obj);
465 }
466
467 HRESULT create_rowset_server(IUnknown *outer, void **obj)
468 {
469     return create_server(outer, &CLSID_wine_rowset_server, obj);
470 }
471
472 typedef struct
473 {
474     const IRowVtbl *row_vtbl;
475     const IRowChangeVtbl *row_change_vtbl;
476
477     LONG ref;
478
479     IWineRowServer *server;
480 } row_proxy;
481
482 static inline row_proxy *impl_from_IRow(IRow *iface)
483 {
484     return (row_proxy *)((char*)iface - FIELD_OFFSET(row_proxy, row_vtbl));
485 }
486
487 static inline row_proxy *impl_from_IRowChange(IRowChange *iface)
488 {
489     return (row_proxy *)((char*)iface - FIELD_OFFSET(row_proxy, row_change_vtbl));
490 }
491
492 static HRESULT WINAPI row_QueryInterface(IRow *iface, REFIID iid, void **obj)
493 {
494     row_proxy *This = impl_from_IRow(iface);
495     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(iid), obj);
496
497     if(IsEqualIID(iid, &IID_IUnknown) ||
498        IsEqualIID(iid, &IID_IRow))
499     {
500         *obj = &This->row_vtbl;
501     }
502     else if(IsEqualIID(iid, &IID_IRowChange))
503     {
504         *obj = &This->row_change_vtbl;
505     }
506     else
507     {
508         FIXME("interface %s not implemented\n", debugstr_guid(iid));
509         return E_NOINTERFACE;
510     }
511
512     IRow_AddRef(iface);
513     return S_OK;
514 }
515
516 static ULONG WINAPI row_AddRef(IRow *iface)
517 {
518     row_proxy *This = impl_from_IRow(iface);
519     TRACE("(%p)\n", This);
520
521     return InterlockedIncrement(&This->ref);
522 }
523
524 static ULONG WINAPI row_Release(IRow *iface)
525 {
526     row_proxy *This = impl_from_IRow(iface);
527     LONG ref;
528
529     TRACE("(%p)\n", This);
530
531     ref = InterlockedDecrement(&This->ref);
532     if(ref == 0)
533     {
534         if(This->server) IWineRowServer_Release(This->server);
535         HeapFree(GetProcessHeap(), 0, This);
536     }
537
538     return ref;
539 }
540
541 static HRESULT WINAPI row_GetColumns(IRow* iface, DBORDINAL cColumns, DBCOLUMNACCESS rgColumns[])
542 {
543     row_proxy *This = impl_from_IRow(iface);
544     DBORDINAL i;
545     wine_getcolumns_in *in_data;
546     wine_getcolumns_out *out_data;
547     HRESULT hr;
548
549     TRACE("(%p)->(%d, %p)\n", This, cColumns, rgColumns);
550
551     in_data = CoTaskMemAlloc(cColumns * sizeof(in_data[0]));
552     out_data = CoTaskMemAlloc(cColumns * sizeof(out_data[0]));
553
554     for(i = 0; i < cColumns; i++)
555     {
556         TRACE("%d:\tdata %p data_len %d status %08x max_len %d type %04x\n", i, rgColumns[i].pData,
557               rgColumns[i].cbDataLen, rgColumns[i].dwStatus, rgColumns[i].cbMaxLen, rgColumns[i].wType);
558         in_data[i].columnid     = rgColumns[i].columnid;
559         in_data[i].max_len      = rgColumns[i].cbMaxLen;
560         in_data[i].type         = rgColumns[i].wType;
561         in_data[i].precision    = rgColumns[i].bPrecision;
562         in_data[i].scale        = rgColumns[i].bScale;
563     }
564
565     hr = IWineRowServer_GetColumns(This->server, cColumns, in_data, out_data);
566
567     for(i = 0; i < cColumns; i++)
568     {
569         rgColumns[i].cbDataLen = out_data[i].data_len;
570         rgColumns[i].dwStatus  = out_data[i].status;
571         if(rgColumns[i].dwStatus == DBSTATUS_S_OK)
572             memcpy(rgColumns[i].pData, &V_I1(&out_data[i].v), out_data[i].data_len);
573     }
574
575     CoTaskMemFree(out_data);
576     CoTaskMemFree(in_data);
577     return hr;
578 }
579
580 static HRESULT WINAPI row_GetSourceRowset(IRow* iface, REFIID riid, IUnknown **ppRowset,
581                                           HROW *phRow)
582 {
583     row_proxy *This = impl_from_IRow(iface);
584
585     FIXME("(%p)->(%s, %p, %p): stub\n", This, debugstr_guid(riid), ppRowset, phRow);
586
587     return E_NOTIMPL;
588 }
589
590 static HRESULT WINAPI row_Open(IRow* iface, IUnknown *pUnkOuter,
591                                DBID *pColumnID, REFGUID rguidColumnType,
592                                DWORD dwBindFlags, REFIID riid, IUnknown **ppUnk)
593 {
594     row_proxy *This = impl_from_IRow(iface);
595
596     FIXME("(%p)->(%p, %p, %s, %08x, %s, %p): stub\n", This, pUnkOuter, pColumnID, debugstr_guid(rguidColumnType),
597           dwBindFlags, debugstr_guid(riid), ppUnk);
598
599     return E_NOTIMPL;
600 }
601
602 static const IRowVtbl row_vtbl =
603 {
604     row_QueryInterface,
605     row_AddRef,
606     row_Release,
607     row_GetColumns,
608     row_GetSourceRowset,
609     row_Open
610 };
611
612 static HRESULT WINAPI row_change_QueryInterface(IRowChange *iface, REFIID iid, void **obj)
613 {
614     row_proxy *This = impl_from_IRowChange(iface);
615     return IUnknown_QueryInterface((IUnknown *)This, iid, obj);
616 }
617
618 static ULONG WINAPI row_change_AddRef(IRowChange *iface)
619 {
620     row_proxy *This = impl_from_IRowChange(iface);
621     return IUnknown_AddRef((IUnknown*)This);
622 }
623
624 static ULONG WINAPI row_change_Release(IRowChange *iface)
625 {
626     row_proxy *This = impl_from_IRowChange(iface);
627     return IUnknown_Release((IUnknown*)This);
628 }
629
630 static HRESULT WINAPI row_change_SetColumns(IRowChange *iface, DBORDINAL cColumns,
631                                             DBCOLUMNACCESS rgColumns[])
632 {
633     row_proxy *This = impl_from_IRowChange(iface);
634     FIXME("(%p)->(%d, %p)\n", This, cColumns, rgColumns);
635     return E_NOTIMPL;
636 }
637
638 static const IRowChangeVtbl row_change_vtbl =
639 {
640     row_change_QueryInterface,
641     row_change_AddRef,
642     row_change_Release,
643     row_change_SetColumns
644 };
645
646 static HRESULT create_row_proxy(IWineRowServer *server, IUnknown **obj)
647 {
648     row_proxy *proxy;
649
650     TRACE("(%p, %p)\n", server, obj);
651     *obj = NULL;
652
653     proxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*proxy));
654     if(!proxy) return E_OUTOFMEMORY;
655
656     proxy->row_vtbl = &row_vtbl;
657     proxy->row_change_vtbl = &row_change_vtbl;
658     proxy->ref = 1;
659     IWineRowServer_AddRef(server);
660     proxy->server = server;
661
662     *obj = (IUnknown*)&proxy->row_vtbl;
663     TRACE("returing %p\n", *obj);
664     return S_OK;
665 }
666
667 typedef struct
668 {
669     const IRowsetVtbl *rowset_vtbl;
670
671     LONG ref;
672
673     IWineRowServer *server;
674 } rowset_proxy;
675
676 static inline rowset_proxy *impl_from_IRowset(IRowset *iface)
677 {
678     return (rowset_proxy *)((char*)iface - FIELD_OFFSET(rowset_proxy, rowset_vtbl));
679 }
680
681 static HRESULT WINAPI rowset_QueryInterface(IRowset *iface, REFIID iid, void **obj)
682 {
683     rowset_proxy *This = impl_from_IRowset(iface);
684     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(iid), obj);
685
686     *obj = NULL;
687
688     if(IsEqualIID(iid, &IID_IUnknown) ||
689        IsEqualIID(iid, &IID_IRowset))
690     {
691         *obj = &This->rowset_vtbl;
692     }
693     else
694     {
695         FIXME("interface %s not implemented\n", debugstr_guid(iid));
696         return E_NOINTERFACE;
697     }
698
699     IRowset_AddRef(iface);
700     return S_OK;
701 }
702
703 static ULONG WINAPI rowset_AddRef(IRowset *iface)
704 {
705     rowset_proxy *This = impl_from_IRowset(iface);
706     TRACE("(%p)\n", This);
707
708     return InterlockedIncrement(&This->ref);
709 }
710
711 static ULONG WINAPI rowset_Release(IRowset *iface)
712 {
713     rowset_proxy *This = impl_from_IRowset(iface);
714     LONG ref;
715
716     TRACE("(%p)\n", This);
717
718     ref = InterlockedDecrement(&This->ref);
719     if(ref == 0)
720     {
721         if(This->server) IWineRowServer_Release(This->server);
722         HeapFree(GetProcessHeap(), 0, This);
723     }
724
725     return ref;
726 }
727
728 static HRESULT WINAPI rowset_AddRefRows(IRowset *iface, DBCOUNTITEM cRows, const HROW rghRows[],
729                                         DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[])
730 {
731     rowset_proxy *This = impl_from_IRowset(iface);
732     HRESULT hr;
733     DBREFCOUNT *refs = rgRefCounts;
734     DBSTATUS *stats = rgRowStatus;
735
736     TRACE("(%p)->(%d, %p, %p, %p)\n", This, cRows, rghRows, rgRefCounts, rgRowStatus);
737
738     if(!refs) refs = CoTaskMemAlloc(cRows * sizeof(refs[0]));
739     if(!stats) stats = CoTaskMemAlloc(cRows * sizeof(stats[0]));
740
741     hr = IWineRowServer_AddRefRows(This->server, cRows, rghRows, refs, stats);
742
743     if(refs != rgRefCounts) CoTaskMemFree(refs);
744     if(stats != rgRowStatus) CoTaskMemFree(stats);
745
746     return hr;
747 }
748
749 static HRESULT WINAPI rowset_GetData(IRowset *iface, HROW hRow, HACCESSOR hAccessor, void *pData)
750 {
751     rowset_proxy *This = impl_from_IRowset(iface);
752
753     FIXME("(%p)->(%lx, %lx, %p): stub\n", This, hRow, hAccessor, pData);
754
755     return E_NOTIMPL;
756 }
757
758 static HRESULT WINAPI rowset_GetNextRows(IRowset *iface, HCHAPTER hReserved, DBROWOFFSET lRowsOffset,
759                                          DBROWCOUNT cRows, DBCOUNTITEM *pcRowObtained, HROW **prghRows)
760 {
761     rowset_proxy *This = impl_from_IRowset(iface);
762     HRESULT hr;
763     HROW *rows = NULL;
764
765     TRACE("(%p)->(%08lx, %d, %d, %p, %p)\n", This, hReserved, lRowsOffset, cRows, pcRowObtained, prghRows);
766
767     hr = IWineRowServer_GetNextRows(This->server, hReserved, lRowsOffset, cRows, pcRowObtained, &rows);
768     if(*prghRows)
769     {
770         memcpy(*prghRows, rows, *pcRowObtained * sizeof(rows[0]));
771         CoTaskMemFree(rows);
772     }
773     else
774         *prghRows = rows;
775
776     return hr;
777 }
778
779 static HRESULT WINAPI rowset_ReleaseRows(IRowset *iface, DBCOUNTITEM cRows, const HROW rghRows[],
780                                          DBROWOPTIONS rgRowOptions[], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[])
781 {
782     rowset_proxy *This = impl_from_IRowset(iface);
783     HRESULT hr;
784     DBROWOPTIONS *options = rgRowOptions;
785     DBREFCOUNT *refs = rgRefCounts;
786     DBROWSTATUS *status = rgRowStatus;
787
788     TRACE("(%p)->(%d, %p, %p, %p, %p)\n", This, cRows, rghRows, rgRowOptions, rgRefCounts, rgRowStatus);
789
790     if(!options)
791     {
792         options = CoTaskMemAlloc(cRows * sizeof(options[0]));
793         memset(options, 0, cRows * sizeof(options[0]));
794     }
795     if(!refs) refs = CoTaskMemAlloc(cRows * sizeof(refs[0]));
796     if(!status) status = CoTaskMemAlloc(cRows * sizeof(status[0]));
797
798     hr = IWineRowServer_ReleaseRows(This->server, cRows, rghRows, options, refs, status);
799
800     if(status != rgRowStatus) CoTaskMemFree(status);
801     if(refs != rgRefCounts) CoTaskMemFree(refs);
802     if(options != rgRowOptions) CoTaskMemFree(options);
803
804     return hr;
805 }
806
807 static HRESULT WINAPI rowset_RestartPosition(IRowset* iface, HCHAPTER hReserved)
808 {
809     rowset_proxy *This = impl_from_IRowset(iface);
810
811     FIXME("(%p)->(%lx): stub\n", This, hReserved);
812
813     return E_NOTIMPL;
814 }
815
816 static const IRowsetVtbl rowset_vtbl =
817 {
818     rowset_QueryInterface,
819     rowset_AddRef,
820     rowset_Release,
821     rowset_AddRefRows,
822     rowset_GetData,
823     rowset_GetNextRows,
824     rowset_ReleaseRows,
825     rowset_RestartPosition
826 };
827
828 HRESULT create_rowset_proxy(IWineRowServer *server, IUnknown **obj)
829 {
830     rowset_proxy *proxy;
831
832     TRACE("(%p, %p)\n", server, obj);
833     *obj = NULL;
834
835     proxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*proxy));
836     if(!proxy) return E_OUTOFMEMORY;
837
838     proxy->rowset_vtbl = &rowset_vtbl;
839     proxy->ref = 1;
840     IWineRowServer_AddRef(server);
841     proxy->server = server;
842
843     *obj = (IUnknown *)&proxy->rowset_vtbl;
844     TRACE("returing %p\n", *obj);
845     return S_OK;
846 }
847
848 static HRESULT create_proxy(IWineRowServer *server, const CLSID *class, IUnknown **obj)
849 {
850     *obj = NULL;
851
852     if(IsEqualGUID(class, &CLSID_wine_row_proxy))
853         return create_row_proxy(server, obj);
854     else if(IsEqualGUID(class, &CLSID_wine_rowset_proxy))
855         return create_rowset_proxy(server, obj);
856     else
857         FIXME("Unhandled proxy class %s\n", debugstr_guid(class));
858     return E_NOTIMPL;
859 }
860
861 /* Marshal impl */
862
863 typedef struct
864 {
865     const IMarshalVtbl *marshal_vtbl;
866
867     LONG ref;
868     CLSID unmarshal_class;
869     IUnknown *outer;
870 } marshal;
871
872 static inline marshal *impl_from_IMarshal(IMarshal *iface)
873 {
874     return (marshal *)((char*)iface - FIELD_OFFSET(marshal, marshal_vtbl));
875 }
876
877 static HRESULT WINAPI marshal_QueryInterface(IMarshal *iface, REFIID iid, void **obj)
878 {
879     marshal *This = impl_from_IMarshal(iface);
880     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(iid), obj);
881
882     if(IsEqualIID(iid, &IID_IUnknown) ||
883        IsEqualIID(iid, &IID_IMarshal))
884     {
885         *obj = iface;
886     }
887     else
888     {
889         FIXME("interface %s not implemented\n", debugstr_guid(iid));
890         *obj = NULL;
891         return E_NOINTERFACE;
892     }
893
894     IMarshal_AddRef(iface);
895     return S_OK;
896 }
897
898 static ULONG WINAPI marshal_AddRef(IMarshal *iface)
899 {
900     marshal *This = impl_from_IMarshal(iface);
901     TRACE("(%p)\n", This);
902     return InterlockedIncrement(&This->ref);
903 }
904
905 static ULONG WINAPI marshal_Release(IMarshal *iface)
906 {
907     marshal *This = impl_from_IMarshal(iface);
908     LONG ref;
909
910     TRACE("(%p)\n", This);
911
912     ref = InterlockedDecrement(&This->ref);
913     if(ref == 0)
914     {
915         HeapFree(GetProcessHeap(), 0, This);
916     }
917
918     return ref;
919 }
920
921 static HRESULT WINAPI marshal_GetUnmarshalClass(IMarshal *iface, REFIID iid, void *obj,
922                                                 DWORD dwDestContext, void *pvDestContext,
923                                                 DWORD mshlflags, CLSID *clsid)
924 {
925     marshal *This = impl_from_IMarshal(iface);
926     TRACE("(%p)->(%s, %p, %08x, %p, %08x, %p)\n", This, debugstr_guid(iid), obj, dwDestContext,
927           pvDestContext, mshlflags, clsid);
928
929     *clsid = This->unmarshal_class;
930     return S_OK;
931 }
932
933 static HRESULT WINAPI marshal_GetMarshalSizeMax(IMarshal *iface, REFIID iid, void *obj,
934                                                 DWORD dwDestContext, void *pvDestContext,
935                                                 DWORD mshlflags, DWORD *size)
936 {
937     marshal *This = impl_from_IMarshal(iface);
938     TRACE("(%p)->(%s, %p, %08x, %p, %08x, %p)\n", This, debugstr_guid(iid), obj, dwDestContext,
939           pvDestContext, mshlflags, size);
940
941     return CoGetMarshalSizeMax(size, &IID_IWineRowServer, This->outer, dwDestContext, pvDestContext,
942                                mshlflags);
943 }
944
945 static HRESULT WINAPI marshal_MarshalInterface(IMarshal *iface, IStream *stream, REFIID iid,
946                                                void *obj, DWORD dwDestContext, void *pvDestContext,
947                                                DWORD mshlflags)
948 {
949     marshal *This = impl_from_IMarshal(iface);
950     TRACE("(%p)->(%p, %s, %p, %08x, %p, %08x)\n", This, stream, debugstr_guid(iid), obj, dwDestContext,
951           pvDestContext, mshlflags);
952
953     return CoMarshalInterface(stream, &IID_IWineRowServer, This->outer, dwDestContext, pvDestContext, mshlflags);
954 }
955
956 static HRESULT WINAPI marshal_UnmarshalInterface(IMarshal *iface, IStream *stream,
957                                                  REFIID iid, void **obj)
958 {
959     marshal *This = impl_from_IMarshal(iface);
960     HRESULT hr;
961     IWineRowServer *server;
962     IUnknown *proxy;
963
964     TRACE("(%p)->(%p, %s, %p)\n", This, stream, debugstr_guid(iid), obj);
965     *obj = NULL;
966
967     hr = CoUnmarshalInterface(stream, &IID_IWineRowServer, (void**)&server);
968     if(SUCCEEDED(hr))
969     {
970         hr = create_proxy(server, &This->unmarshal_class, &proxy);
971         if(SUCCEEDED(hr))
972         {
973             hr = IUnknown_QueryInterface(proxy, iid, obj);
974             IUnknown_Release(proxy);
975         }
976         IWineRowServer_Release(server);
977     }
978
979     TRACE("returing %p\n", *obj);
980     return hr;
981 }
982
983 static HRESULT WINAPI marshal_ReleaseMarshalData(IMarshal *iface, IStream *stream)
984 {
985     marshal *This = impl_from_IMarshal(iface);
986     TRACE("(%p)->(%p)\n", This, stream);
987     return CoReleaseMarshalData(stream);
988 }
989
990 static HRESULT WINAPI marshal_DisconnectObject(IMarshal *iface, DWORD dwReserved)
991 {
992     marshal *This = impl_from_IMarshal(iface);
993     FIXME("(%p)->(%08x)\n", This, dwReserved);
994
995     return E_NOTIMPL;
996 }
997
998 static const IMarshalVtbl marshal_vtbl =
999 {
1000     marshal_QueryInterface,
1001     marshal_AddRef,
1002     marshal_Release,
1003     marshal_GetUnmarshalClass,
1004     marshal_GetMarshalSizeMax,
1005     marshal_MarshalInterface,
1006     marshal_UnmarshalInterface,
1007     marshal_ReleaseMarshalData,
1008     marshal_DisconnectObject
1009 };
1010
1011 static HRESULT create_marshal(IUnknown *outer, const CLSID *class, void **obj)
1012 {
1013     marshal *marshal;
1014
1015     TRACE("(%p, %p)\n", outer, obj);
1016     *obj = NULL;
1017
1018     marshal = HeapAlloc(GetProcessHeap(), 0, sizeof(*marshal));
1019     if(!marshal) return E_OUTOFMEMORY;
1020
1021     marshal->unmarshal_class = *class;
1022     marshal->outer = outer; /* don't ref outer unk */
1023     marshal->marshal_vtbl = &marshal_vtbl;
1024     marshal->ref = 1;
1025
1026     *obj = &marshal->marshal_vtbl;
1027     TRACE("returing %p\n", *obj);
1028     return S_OK;
1029 }
1030
1031 HRESULT create_row_marshal(IUnknown *outer, void **obj)
1032 {
1033     TRACE("(%p, %p)\n", outer, obj);
1034     return create_marshal(outer, &CLSID_wine_row_proxy, obj);
1035 }
1036
1037 HRESULT create_rowset_marshal(IUnknown *outer, void **obj)
1038 {
1039     TRACE("(%p, %p)\n", outer, obj);
1040     return create_marshal(outer, &CLSID_wine_rowset_proxy, obj);
1041 }