msvcr90: Added _get/set_invalid_parameter_handler implementation.
[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     IRow *row;
223     HRESULT hr;
224     IWineRowServer *new_server;
225     IMarshal *marshal;
226     IUnknown *obj;
227
228     TRACE("(%p)->(%p, %p, %s, %08x, %s, %p)\n", This, pUnkOuter, pColumnID, debugstr_guid(rguidColumnType),
229           dwBindFlags, debugstr_guid(riid), ppUnk);
230
231     *ppUnk = NULL;
232
233     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRow, (void**)&row);
234     if(FAILED(hr)) return hr;
235
236     if(IsEqualGUID(rguidColumnType, &DBGUID_ROWSET))
237         hr = CoCreateInstance(&CLSID_wine_rowset_server, NULL, CLSCTX_INPROC_SERVER, &IID_IWineRowServer, (void**)&new_server);
238     else
239     {
240         FIXME("Unhandled object %s\n", debugstr_guid(rguidColumnType));
241         hr = E_NOTIMPL;
242     }
243
244     if(FAILED(hr))
245     {
246         IRow_Release(row);
247         return hr;
248     }
249
250     IWineRowServer_GetMarshal(new_server, &marshal);
251     hr = IRow_Open(row, (IUnknown*)marshal, pColumnID, rguidColumnType, dwBindFlags, &IID_IUnknown, &obj);
252     IMarshal_Release(marshal);
253     IRow_Release(row);
254
255     if(FAILED(hr))
256     {
257         IWineRowServer_Release(new_server);
258         return hr;
259     }
260
261     IWineRowServer_SetInnerUnk(new_server, obj);
262     hr = IUnknown_QueryInterface(obj, riid, (void**)ppUnk);
263     IUnknown_Release(obj);
264
265     TRACE("returning %08x\n", hr);
266     return hr;
267 }
268
269 static HRESULT WINAPI server_SetColumns(IWineRowServer* iface, DBORDINAL num_cols,
270                                         wine_setcolumns_in *in_data, DBSTATUS *status)
271 {
272     server *This = impl_from_IWineRowServer(iface);
273     HRESULT hr;
274     DBORDINAL i;
275     DBCOLUMNACCESS *cols;
276     IRowChange *row_change;
277
278     TRACE("(%p)->(%d, %p, %p)\n", This, num_cols, in_data, status);
279     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowChange, (void**)&row_change);
280     if(FAILED(hr)) return hr;
281
282     cols = CoTaskMemAlloc(num_cols * sizeof(cols[0]));
283
284     for(i = 0; i < num_cols; i++)
285     {
286         TRACE("%d:\ttype %04x\n", i, in_data[i].type);
287         cols[i].pData        = CoTaskMemAlloc(db_type_size(in_data[i].type, in_data[i].max_len));
288         memcpy(cols[i].pData, &V_I1(&in_data[i].v), db_type_size(in_data[i].type, in_data[i].max_len));
289         cols[i].columnid     = in_data[i].columnid;
290         cols[i].cbDataLen    = in_data[i].data_len;
291         cols[i].dwStatus     = in_data[i].status;
292         cols[i].cbMaxLen     = in_data[i].max_len;
293         cols[i].wType        = in_data[i].type;
294         cols[i].bPrecision   = in_data[i].precision;
295         cols[i].bScale       = in_data[i].scale;
296     }
297
298     hr = IRowChange_SetColumns(row_change, num_cols, cols);
299     IRowChange_Release(row_change);
300
301     for(i = 0; i < num_cols; i++)
302     {
303         CoTaskMemFree(cols[i].pData);
304         status[i] = cols[i].dwStatus;
305     }
306
307     CoTaskMemFree(cols);
308
309     return hr;
310 }
311
312 static HRESULT WINAPI server_AddRefRows(IWineRowServer* iface, DBCOUNTITEM cRows,
313                                         const HROW rghRows[], DBREFCOUNT rgRefCounts[],
314                                         DBROWSTATUS rgRowStatus[])
315 {
316     server *This = impl_from_IWineRowServer(iface);
317     IRowset *rowset;
318     HRESULT hr;
319
320     TRACE("(%p)->(%d, %p, %p, %p)\n", This, cRows, rghRows, rgRefCounts, rgRowStatus);
321
322     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowset, (void**)&rowset);
323     if(FAILED(hr)) return hr;
324
325     hr = IRowset_AddRefRows(rowset, cRows, rghRows, rgRefCounts, rgRowStatus);
326
327     IRowset_Release(rowset);
328     TRACE("returning %08x\n", hr);
329     return hr;
330 }
331
332 static HRESULT WINAPI server_GetData(IWineRowServer* iface, HROW hRow,
333                                      HACCESSOR hAccessor, BYTE *pData, DWORD size)
334 {
335     server *This = impl_from_IWineRowServer(iface);
336     IRowset *rowset;
337     HRESULT hr;
338
339     TRACE("(%p)->(%08lx, %08lx, %p, %d)\n", This, hRow, hAccessor, pData, size);
340
341     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowset, (void**)&rowset);
342     if(FAILED(hr)) return hr;
343
344     hr = IRowset_GetData(rowset, hRow, hAccessor, pData);
345
346     IRowset_Release(rowset);
347     TRACE("returning %08x\n", hr);
348     return hr;
349 }
350
351 static HRESULT WINAPI server_GetNextRows(IWineRowServer* iface, HCHAPTER hReserved, DBROWOFFSET lRowsOffset,
352                                          DBROWCOUNT cRows, DBCOUNTITEM *pcRowObtained, HROW **prghRows)
353 {
354     server *This = impl_from_IWineRowServer(iface);
355     IRowset *rowset;
356     HRESULT hr;
357
358     TRACE("(%p)->(%08lx, %d, %d, %p, %p)\n", This, hReserved, lRowsOffset, cRows, pcRowObtained, prghRows);
359
360     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowset, (void**)&rowset);
361     if(FAILED(hr)) return hr;
362
363     *prghRows = NULL;
364
365     hr = IRowset_GetNextRows(rowset, hReserved, lRowsOffset, cRows, pcRowObtained, prghRows);
366     IRowset_Release(rowset);
367     TRACE("returning %08x, got %d rows\n", hr, *pcRowObtained);
368     return hr;
369 }
370
371 static HRESULT WINAPI server_ReleaseRows(IWineRowServer* iface, DBCOUNTITEM cRows, const HROW rghRows[],
372                                          DBROWOPTIONS rgRowOptions[], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[])
373 {
374     server *This = impl_from_IWineRowServer(iface);
375     IRowset *rowset;
376     HRESULT hr;
377
378     TRACE("(%p)->(%d, %p, %p, %p, %p)\n", This, cRows, rghRows, rgRowOptions, rgRefCounts, rgRowStatus);
379
380     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowset, (void**)&rowset);
381     if(FAILED(hr)) return hr;
382
383     hr = IRowset_ReleaseRows(rowset, cRows, rghRows, rgRowOptions, rgRefCounts, rgRowStatus);
384     IRowset_Release(rowset);
385
386     TRACE("returning %08x\n", hr);
387     return hr;
388 }
389
390 static HRESULT WINAPI server_RestartPosition(IWineRowServer* iface, HCHAPTER hReserved)
391 {
392     server *This = impl_from_IWineRowServer(iface);
393     FIXME("(%p)->(%08lx): stub\n", This, hReserved);
394     return E_NOTIMPL;
395 }
396
397 static HRESULT WINAPI server_Compare(IWineRowServer *iface, HCHAPTER hReserved, DBBKMARK cbBookmark1,
398                                      const BYTE *pBookmark1, DBBKMARK cbBookmark2, const BYTE *pBookmark2,
399                                      DBCOMPARE *pComparison)
400 {
401     server *This = impl_from_IWineRowServer(iface);
402     FIXME("(%p): stub\n", This);
403     return E_NOTIMPL;
404 }
405
406 static HRESULT WINAPI server_GetRowsAt(IWineRowServer *iface, HWATCHREGION hReserved1, HCHAPTER hReserved2,
407                                        DBBKMARK cbBookmark, const BYTE *pBookmark, DBROWOFFSET lRowsOffset,
408                                        DBROWCOUNT cRows, DBCOUNTITEM *pcRowsObtained, HROW **prghRows)
409 {
410     server *This = impl_from_IWineRowServer(iface);
411     IRowsetLocate *rowsetlocate;
412     HRESULT hr;
413
414     TRACE("(%p)->(%08lx, %08lx, %d, %p, %d, %d, %p, %p\n", This, hReserved1, hReserved2, cbBookmark, pBookmark, lRowsOffset, cRows,
415           pcRowsObtained, prghRows);
416
417     *prghRows = NULL;
418
419     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowsetLocate, (void**)&rowsetlocate);
420     if(FAILED(hr)) return hr;
421
422     hr = IRowsetLocate_GetRowsAt(rowsetlocate, hReserved1, hReserved2, cbBookmark, pBookmark, lRowsOffset,
423                                  cRows, pcRowsObtained, prghRows);
424     IRowsetLocate_Release(rowsetlocate);
425
426     TRACE("returning %08x\n", hr);
427     return hr;
428 }
429
430 static HRESULT WINAPI server_GetRowsByBookmark(IWineRowServer *iface, HCHAPTER hReserved, DBCOUNTITEM cRows,
431                                                const DBBKMARK rgcbBookmarks[], const BYTE * rgpBookmarks[],
432                                                HROW rghRows[], DBROWSTATUS rgRowStatus[])
433 {
434     server *This = impl_from_IWineRowServer(iface);
435     FIXME("(%p): stub\n", This);
436     return E_NOTIMPL;
437 }
438
439 static HRESULT WINAPI server_Hash(IWineRowServer *iface, HCHAPTER hReserved, DBBKMARK cBookmarks,
440                                   const DBBKMARK rgcbBookmarks[], const BYTE * rgpBookmarks[],
441                                   DBHASHVALUE rgHashedValues[], DBROWSTATUS rgBookmarkStatus[])
442 {
443     server *This = impl_from_IWineRowServer(iface);
444     FIXME("(%p): stub\n", This);
445     return E_NOTIMPL;
446 }
447
448 static HRESULT WINAPI server_GetProperties(IWineRowServer* iface, ULONG cPropertyIDSets,
449                                            const DBPROPIDSET *rgPropertyIDSets, ULONG *pcPropertySets,
450                                            DBPROPSET **prgPropertySets)
451 {
452     server *This = impl_from_IWineRowServer(iface);
453     IRowsetInfo *rowsetinfo;
454     HRESULT hr;
455
456     TRACE("(%p)->(%d, %p, %p, %p)\n", This, cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
457
458     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowsetInfo, (void**)&rowsetinfo);
459     if(FAILED(hr)) return hr;
460
461     hr = IRowsetInfo_GetProperties(rowsetinfo, cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
462     IRowsetInfo_Release(rowsetinfo);
463
464     TRACE("returning %08x\n", hr);
465     return hr;
466 }
467
468 static HRESULT WINAPI server_GetReferencedRowset(IWineRowServer* iface, DBORDINAL iOrdinal,
469                                                  REFIID riid, IUnknown **ppReferencedRowset)
470 {
471     server *This = impl_from_IWineRowServer(iface);
472     FIXME("(%p): stub\n", This);
473     return E_NOTIMPL;
474 }
475
476 static HRESULT WINAPI server_GetSpecification(IWineRowServer* iface, REFIID riid,
477                                                IUnknown **ppSpecification)
478 {
479     server *This = impl_from_IWineRowServer(iface);
480     FIXME("(%p): stub\n", This);
481     return E_NOTIMPL;
482 }
483
484 static HRESULT WINAPI server_AddRefAccessor(IWineRowServer* iface, HACCESSOR hAccessor,
485                                             DBREFCOUNT *pcRefCount)
486 {
487     server *This = impl_from_IWineRowServer(iface);
488     FIXME("(%p): stub\n", This);
489     return E_NOTIMPL;
490 }
491
492 static HRESULT WINAPI server_CreateAccessor(IWineRowServer* iface, DBACCESSORFLAGS dwAccessorFlags,
493                                             DBCOUNTITEM cBindings, const DBBINDING *rgBindings, DBLENGTH cbRowSize,
494                                             HACCESSOR *phAccessor, DBBINDSTATUS *rgStatus)
495 {
496     server *This = impl_from_IWineRowServer(iface);
497     HRESULT hr;
498     IAccessor *accessor;
499
500     TRACE("(%p)->(%08x, %d, %p, %d, %p, %p)\n", This, dwAccessorFlags, cBindings, rgBindings, cbRowSize, phAccessor, rgStatus);
501
502     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IAccessor, (void**)&accessor);
503     if(FAILED(hr)) return hr;
504
505     hr = IAccessor_CreateAccessor(accessor, dwAccessorFlags, cBindings, rgBindings, cbRowSize, phAccessor, rgStatus);
506     IAccessor_Release(accessor);
507
508     TRACE("returning %08x, accessor %08lx\n", hr, *phAccessor);
509     return hr;
510 }
511
512 static HRESULT WINAPI server_GetBindings(IWineRowServer* iface, HACCESSOR hAccessor,
513                                          DBACCESSORFLAGS *pdwAccessorFlags, DBCOUNTITEM *pcBindings,
514                                          DBBINDING **prgBindings)
515 {
516     server *This = impl_from_IWineRowServer(iface);
517     HRESULT hr;
518     IAccessor *accessor;
519
520     TRACE("(%p)->(%08lx, %p, %p, %p)\n", This, hAccessor, pdwAccessorFlags, pcBindings, prgBindings);
521
522     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IAccessor, (void**)&accessor);
523     if(FAILED(hr)) return hr;
524
525     hr = IAccessor_GetBindings(accessor, hAccessor, pdwAccessorFlags, pcBindings, prgBindings);
526     IAccessor_Release(accessor);
527
528     TRACE("returning %08x\n", hr);
529     return hr;
530 }
531
532 static HRESULT WINAPI server_ReleaseAccessor(IWineRowServer* iface, HACCESSOR hAccessor,
533                                              DBREFCOUNT *pcRefCount)
534 {
535     server *This = impl_from_IWineRowServer(iface);
536     HRESULT hr;
537     IAccessor *accessor;
538
539     TRACE("(%p)->(%08lx, %p)\n", This, hAccessor, pcRefCount);
540
541     hr = IUnknown_QueryInterface(This->inner_unk, &IID_IAccessor, (void**)&accessor);
542     if(FAILED(hr)) return hr;
543
544     hr = IAccessor_ReleaseAccessor(accessor, hAccessor, pcRefCount);
545     IAccessor_Release(accessor);
546
547     return hr;
548 }
549
550 static const IWineRowServerVtbl server_vtbl =
551 {
552     server_QueryInterface,
553     server_AddRef,
554     server_Release,
555     server_SetInnerUnk,
556     server_GetMarshal,
557     server_GetColumns,
558     server_GetSourceRowset,
559     server_Open,
560     server_SetColumns,
561     server_AddRefRows,
562     server_GetData,
563     server_GetNextRows,
564     server_ReleaseRows,
565     server_RestartPosition,
566     server_Compare,
567     server_GetRowsAt,
568     server_GetRowsByBookmark,
569     server_Hash,
570     server_GetProperties,
571     server_GetReferencedRowset,
572     server_GetSpecification,
573     server_AddRefAccessor,
574     server_CreateAccessor,
575     server_GetBindings,
576     server_ReleaseAccessor
577 };
578
579 static HRESULT create_server(IUnknown *outer, const CLSID *class, void **obj)
580 {
581     server *server;
582     TRACE("(%p, %s, %p)\n", outer, debugstr_guid(class), obj);
583
584     *obj = NULL;
585
586     server = HeapAlloc(GetProcessHeap(), 0, sizeof(*server));
587     if(!server) return E_OUTOFMEMORY;
588
589     server->vtbl = &server_vtbl;
590     server->ref = 1;
591     server->class = *class;
592     server->inner_unk = NULL;
593     if(IsEqualGUID(class, &CLSID_wine_row_server))
594         create_row_marshal((IUnknown*)server, (void**)&server->marshal);
595     else if(IsEqualGUID(class, &CLSID_wine_rowset_server))
596         create_rowset_marshal((IUnknown*)server, (void**)&server->marshal);
597     else
598         ERR("create_server called with class %s\n", debugstr_guid(class));
599
600     *obj = server;
601     return S_OK;
602 }
603
604 HRESULT create_row_server(IUnknown *outer, void **obj)
605 {
606     return create_server(outer, &CLSID_wine_row_server, obj);
607 }
608
609 HRESULT create_rowset_server(IUnknown *outer, void **obj)
610 {
611     return create_server(outer, &CLSID_wine_rowset_server, obj);
612 }
613
614 typedef struct
615 {
616     const IRowVtbl *row_vtbl;
617     const IRowChangeVtbl *row_change_vtbl;
618
619     LONG ref;
620
621     IWineRowServer *server;
622 } row_proxy;
623
624 static inline row_proxy *impl_from_IRow(IRow *iface)
625 {
626     return (row_proxy *)((char*)iface - FIELD_OFFSET(row_proxy, row_vtbl));
627 }
628
629 static inline row_proxy *impl_from_IRowChange(IRowChange *iface)
630 {
631     return (row_proxy *)((char*)iface - FIELD_OFFSET(row_proxy, row_change_vtbl));
632 }
633
634 static HRESULT WINAPI row_QueryInterface(IRow *iface, REFIID iid, void **obj)
635 {
636     row_proxy *This = impl_from_IRow(iface);
637     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(iid), obj);
638
639     if(IsEqualIID(iid, &IID_IUnknown) ||
640        IsEqualIID(iid, &IID_IRow))
641     {
642         *obj = &This->row_vtbl;
643     }
644     else if(IsEqualIID(iid, &IID_IRowChange))
645     {
646         *obj = &This->row_change_vtbl;
647     }
648     else
649     {
650         FIXME("interface %s not implemented\n", debugstr_guid(iid));
651         return E_NOINTERFACE;
652     }
653
654     IRow_AddRef(iface);
655     return S_OK;
656 }
657
658 static ULONG WINAPI row_AddRef(IRow *iface)
659 {
660     row_proxy *This = impl_from_IRow(iface);
661     TRACE("(%p)\n", This);
662
663     return InterlockedIncrement(&This->ref);
664 }
665
666 static ULONG WINAPI row_Release(IRow *iface)
667 {
668     row_proxy *This = impl_from_IRow(iface);
669     LONG ref;
670
671     TRACE("(%p)\n", This);
672
673     ref = InterlockedDecrement(&This->ref);
674     if(ref == 0)
675     {
676         if(This->server) IWineRowServer_Release(This->server);
677         HeapFree(GetProcessHeap(), 0, This);
678     }
679
680     return ref;
681 }
682
683 static HRESULT WINAPI row_GetColumns(IRow* iface, DBORDINAL cColumns, DBCOLUMNACCESS rgColumns[])
684 {
685     row_proxy *This = impl_from_IRow(iface);
686     DBORDINAL i;
687     wine_getcolumns_in *in_data;
688     wine_getcolumns_out *out_data;
689     HRESULT hr;
690
691     TRACE("(%p)->(%d, %p)\n", This, cColumns, rgColumns);
692
693     in_data = CoTaskMemAlloc(cColumns * sizeof(in_data[0]));
694     out_data = CoTaskMemAlloc(cColumns * sizeof(out_data[0]));
695
696     for(i = 0; i < cColumns; i++)
697     {
698         TRACE("%d:\tdata %p data_len %d status %08x max_len %d type %04x\n", i, rgColumns[i].pData,
699               rgColumns[i].cbDataLen, rgColumns[i].dwStatus, rgColumns[i].cbMaxLen, rgColumns[i].wType);
700         in_data[i].columnid     = rgColumns[i].columnid;
701         in_data[i].max_len      = rgColumns[i].cbMaxLen;
702         in_data[i].type         = rgColumns[i].wType;
703         in_data[i].precision    = rgColumns[i].bPrecision;
704         in_data[i].scale        = rgColumns[i].bScale;
705     }
706
707     hr = IWineRowServer_GetColumns(This->server, cColumns, in_data, out_data);
708
709     for(i = 0; i < cColumns; i++)
710     {
711         rgColumns[i].cbDataLen = out_data[i].data_len;
712         rgColumns[i].dwStatus  = out_data[i].status;
713         if(rgColumns[i].dwStatus == DBSTATUS_S_OK)
714             memcpy(rgColumns[i].pData, &V_I1(&out_data[i].v), out_data[i].data_len);
715     }
716
717     CoTaskMemFree(out_data);
718     CoTaskMemFree(in_data);
719     return hr;
720 }
721
722 static HRESULT WINAPI row_GetSourceRowset(IRow* iface, REFIID riid, IUnknown **ppRowset,
723                                           HROW *phRow)
724 {
725     row_proxy *This = impl_from_IRow(iface);
726
727     FIXME("(%p)->(%s, %p, %p): stub\n", This, debugstr_guid(riid), ppRowset, phRow);
728
729     return E_NOTIMPL;
730 }
731
732 static HRESULT WINAPI row_Open(IRow* iface, IUnknown *pUnkOuter,
733                                DBID *pColumnID, REFGUID rguidColumnType,
734                                DWORD dwBindFlags, REFIID riid, IUnknown **ppUnk)
735 {
736     row_proxy *This = impl_from_IRow(iface);
737
738     TRACE("(%p)->(%p, %p, %s, %08x, %s, %p)\n", This, pUnkOuter, pColumnID, debugstr_guid(rguidColumnType),
739           dwBindFlags, debugstr_guid(riid), ppUnk);
740     if(pUnkOuter)
741     {
742         FIXME("Aggregation not supported\n");
743         return CLASS_E_NOAGGREGATION;
744     }
745
746     return IWineRowServer_Open(This->server, pUnkOuter, pColumnID, rguidColumnType, dwBindFlags, riid, ppUnk);
747 }
748
749 static const IRowVtbl row_vtbl =
750 {
751     row_QueryInterface,
752     row_AddRef,
753     row_Release,
754     row_GetColumns,
755     row_GetSourceRowset,
756     row_Open
757 };
758
759 static HRESULT WINAPI row_change_QueryInterface(IRowChange *iface, REFIID iid, void **obj)
760 {
761     row_proxy *This = impl_from_IRowChange(iface);
762     return IUnknown_QueryInterface((IUnknown *)This, iid, obj);
763 }
764
765 static ULONG WINAPI row_change_AddRef(IRowChange *iface)
766 {
767     row_proxy *This = impl_from_IRowChange(iface);
768     return IUnknown_AddRef((IUnknown*)This);
769 }
770
771 static ULONG WINAPI row_change_Release(IRowChange *iface)
772 {
773     row_proxy *This = impl_from_IRowChange(iface);
774     return IUnknown_Release((IUnknown*)This);
775 }
776
777 static HRESULT WINAPI row_change_SetColumns(IRowChange *iface, DBORDINAL cColumns,
778                                             DBCOLUMNACCESS rgColumns[])
779 {
780     row_proxy *This = impl_from_IRowChange(iface);
781     HRESULT hr;
782     wine_setcolumns_in *in_data;
783     DBSTATUS *status;
784     DBORDINAL i;
785
786     TRACE("(%p)->(%d, %p)\n", This, cColumns, rgColumns);
787
788     in_data = CoTaskMemAlloc(cColumns * sizeof(in_data[0]));
789     status = CoTaskMemAlloc(cColumns * sizeof(status[0]));
790
791     for(i = 0; i < cColumns; i++)
792     {
793         TRACE("%d: wtype %04x max %08x len %08x\n", i, rgColumns[i].wType, rgColumns[i].cbMaxLen, rgColumns[i].cbDataLen);
794         V_VT(&in_data[i].v) = rgColumns[i].wType;
795         memcpy(&V_I1(&in_data[i].v), rgColumns[i].pData, db_type_size(rgColumns[i].wType, rgColumns[i].cbDataLen));
796         in_data[i].columnid = rgColumns[i].columnid;
797         in_data[i].data_len = rgColumns[i].cbDataLen;
798         in_data[i].status = rgColumns[i].dwStatus;
799         in_data[i].max_len = rgColumns[i].cbMaxLen;
800         in_data[i].type = rgColumns[i].wType;
801         in_data[i].precision = rgColumns[i].bPrecision;
802         in_data[i].scale = rgColumns[i].bScale;
803     }
804
805     hr = IWineRowServer_SetColumns(This->server, cColumns, in_data, status);
806
807     for(i = 0; i < cColumns; i++)
808         rgColumns[i].dwStatus = status[i];
809
810     CoTaskMemFree(status);
811     CoTaskMemFree(in_data);
812
813     return hr;
814 }
815
816 static const IRowChangeVtbl row_change_vtbl =
817 {
818     row_change_QueryInterface,
819     row_change_AddRef,
820     row_change_Release,
821     row_change_SetColumns
822 };
823
824 static HRESULT create_row_proxy(IWineRowServer *server, IUnknown **obj)
825 {
826     row_proxy *proxy;
827
828     TRACE("(%p, %p)\n", server, obj);
829     *obj = NULL;
830
831     proxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*proxy));
832     if(!proxy) return E_OUTOFMEMORY;
833
834     proxy->row_vtbl = &row_vtbl;
835     proxy->row_change_vtbl = &row_change_vtbl;
836     proxy->ref = 1;
837     IWineRowServer_AddRef(server);
838     proxy->server = server;
839
840     *obj = (IUnknown*)&proxy->row_vtbl;
841     TRACE("returning %p\n", *obj);
842     return S_OK;
843 }
844
845 typedef struct
846 {
847     const IRowsetVtbl *rowset_vtbl;
848     const IRowsetLocateVtbl *rowsetlocate_vtbl;
849     const IRowsetInfoVtbl *rowsetinfo_vtbl;
850     const IAccessorVtbl *accessor_vtbl;
851
852     LONG ref;
853
854     IWineRowServer *server;
855 } rowset_proxy;
856
857 static inline rowset_proxy *impl_from_IRowset(IRowset *iface)
858 {
859     return (rowset_proxy *)((char*)iface - FIELD_OFFSET(rowset_proxy, rowset_vtbl));
860 }
861
862 static inline rowset_proxy *impl_from_IRowsetLocate(IRowsetLocate *iface)
863 {
864     return (rowset_proxy *)((char*)iface - FIELD_OFFSET(rowset_proxy, rowsetlocate_vtbl));
865 }
866
867 static inline rowset_proxy *impl_from_IRowsetInfo(IRowsetInfo *iface)
868 {
869     return (rowset_proxy *)((char*)iface - FIELD_OFFSET(rowset_proxy, rowsetinfo_vtbl));
870 }
871
872 static inline rowset_proxy *impl_from_IAccessor(IAccessor *iface)
873 {
874     return (rowset_proxy *)((char*)iface - FIELD_OFFSET(rowset_proxy, accessor_vtbl));
875 }
876
877 static HRESULT WINAPI rowset_QueryInterface(IRowset *iface, REFIID iid, void **obj)
878 {
879     rowset_proxy *This = impl_from_IRowset(iface);
880     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(iid), obj);
881
882     *obj = NULL;
883
884     if(IsEqualIID(iid, &IID_IUnknown) ||
885        IsEqualIID(iid, &IID_IRowset))
886     {
887         *obj = &This->rowset_vtbl;
888     }
889     else if(IsEqualIID(iid, &IID_IRowsetLocate))
890     {
891         *obj = &This->rowsetlocate_vtbl;
892     }
893     else if(IsEqualIID(iid, &IID_IRowsetInfo))
894     {
895         *obj = &This->rowsetinfo_vtbl;
896     }
897     else if(IsEqualIID(iid, &IID_IAccessor))
898     {
899         *obj = &This->accessor_vtbl;
900     }
901     else
902     {
903         FIXME("interface %s not implemented\n", debugstr_guid(iid));
904         return E_NOINTERFACE;
905     }
906
907     IRowset_AddRef(iface);
908     return S_OK;
909 }
910
911 static ULONG WINAPI rowset_AddRef(IRowset *iface)
912 {
913     rowset_proxy *This = impl_from_IRowset(iface);
914     TRACE("(%p)\n", This);
915
916     return InterlockedIncrement(&This->ref);
917 }
918
919 static ULONG WINAPI rowset_Release(IRowset *iface)
920 {
921     rowset_proxy *This = impl_from_IRowset(iface);
922     LONG ref;
923
924     TRACE("(%p)\n", This);
925
926     ref = InterlockedDecrement(&This->ref);
927     if(ref == 0)
928     {
929         if(This->server) IWineRowServer_Release(This->server);
930         HeapFree(GetProcessHeap(), 0, This);
931     }
932
933     return ref;
934 }
935
936 static HRESULT WINAPI rowset_AddRefRows(IRowset *iface, DBCOUNTITEM cRows, const HROW rghRows[],
937                                         DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[])
938 {
939     rowset_proxy *This = impl_from_IRowset(iface);
940     HRESULT hr;
941     DBREFCOUNT *refs = rgRefCounts;
942     DBSTATUS *stats = rgRowStatus;
943
944     TRACE("(%p)->(%d, %p, %p, %p)\n", This, cRows, rghRows, rgRefCounts, rgRowStatus);
945
946     if(!refs) refs = CoTaskMemAlloc(cRows * sizeof(refs[0]));
947     if(!stats) stats = CoTaskMemAlloc(cRows * sizeof(stats[0]));
948
949     hr = IWineRowServer_AddRefRows(This->server, cRows, rghRows, refs, stats);
950
951     if(refs != rgRefCounts) CoTaskMemFree(refs);
952     if(stats != rgRowStatus) CoTaskMemFree(stats);
953
954     return hr;
955 }
956
957 static HRESULT WINAPI rowset_GetData(IRowset *iface, HROW hRow, HACCESSOR hAccessor, void *pData)
958 {
959     rowset_proxy *This = impl_from_IRowset(iface);
960     HRESULT hr;
961     IAccessor *accessor;
962     DBACCESSORFLAGS flags;
963     DBCOUNTITEM count, i;
964     DBBINDING *bindings;
965     DWORD max_len = 0;
966
967     TRACE("(%p)->(%lx, %lx, %p)\n", This, hRow, hAccessor, pData);
968
969     hr = IRowset_QueryInterface(iface, &IID_IAccessor, (void**)&accessor);
970     if(FAILED(hr)) return hr;
971
972     hr = IAccessor_GetBindings(accessor, hAccessor, &flags, &count, &bindings);
973     IAccessor_Release(accessor);
974     if(FAILED(hr)) return hr;
975
976     TRACE("got %d bindings\n", count);
977     for(i = 0; i < count; i++)
978     {
979         TRACE("%d\tord %d offs: val %d len %d stat %d, part %x, max len %d type %04x\n",
980               i, bindings[i].iOrdinal, bindings[i].obValue, bindings[i].obLength, bindings[i].obStatus,
981               bindings[i].dwPart, bindings[i].cbMaxLen, bindings[i].wType);
982         if(bindings[i].dwPart & DBPART_LENGTH && bindings[i].obLength >= max_len)
983             max_len = bindings[i].obLength + sizeof(DBLENGTH);
984         if(bindings[i].dwPart & DBPART_STATUS && bindings[i].obStatus >= max_len)
985             max_len = bindings[i].obStatus + sizeof(DWORD);
986         if(bindings[i].dwPart & DBPART_VALUE && bindings[i].obValue >= max_len)
987             max_len = bindings[i].obValue + db_type_size(bindings[i].wType, bindings[i].cbMaxLen);
988
989     }
990     TRACE("max_len %d\n", max_len);
991
992     CoTaskMemFree(bindings);
993
994     hr = IWineRowServer_GetData(This->server, hRow, hAccessor, pData, max_len);
995
996     return hr;
997 }
998
999 static HRESULT WINAPI rowset_GetNextRows(IRowset *iface, HCHAPTER hReserved, DBROWOFFSET lRowsOffset,
1000                                          DBROWCOUNT cRows, DBCOUNTITEM *pcRowObtained, HROW **prghRows)
1001 {
1002     rowset_proxy *This = impl_from_IRowset(iface);
1003     HRESULT hr;
1004     HROW *rows = NULL;
1005
1006     TRACE("(%p)->(%08lx, %d, %d, %p, %p)\n", This, hReserved, lRowsOffset, cRows, pcRowObtained, prghRows);
1007
1008     hr = IWineRowServer_GetNextRows(This->server, hReserved, lRowsOffset, cRows, pcRowObtained, &rows);
1009     if(*prghRows)
1010     {
1011         memcpy(*prghRows, rows, *pcRowObtained * sizeof(rows[0]));
1012         CoTaskMemFree(rows);
1013     }
1014     else
1015         *prghRows = rows;
1016
1017     return hr;
1018 }
1019
1020 static HRESULT WINAPI rowset_ReleaseRows(IRowset *iface, DBCOUNTITEM cRows, const HROW rghRows[],
1021                                          DBROWOPTIONS rgRowOptions[], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[])
1022 {
1023     rowset_proxy *This = impl_from_IRowset(iface);
1024     HRESULT hr;
1025     DBROWOPTIONS *options = rgRowOptions;
1026     DBREFCOUNT *refs = rgRefCounts;
1027     DBROWSTATUS *status = rgRowStatus;
1028
1029     TRACE("(%p)->(%d, %p, %p, %p, %p)\n", This, cRows, rghRows, rgRowOptions, rgRefCounts, rgRowStatus);
1030
1031     if(!options)
1032     {
1033         options = CoTaskMemAlloc(cRows * sizeof(options[0]));
1034         memset(options, 0, cRows * sizeof(options[0]));
1035     }
1036     if(!refs) refs = CoTaskMemAlloc(cRows * sizeof(refs[0]));
1037     if(!status) status = CoTaskMemAlloc(cRows * sizeof(status[0]));
1038
1039     hr = IWineRowServer_ReleaseRows(This->server, cRows, rghRows, options, refs, status);
1040
1041     if(status != rgRowStatus) CoTaskMemFree(status);
1042     if(refs != rgRefCounts) CoTaskMemFree(refs);
1043     if(options != rgRowOptions) CoTaskMemFree(options);
1044
1045     return hr;
1046 }
1047
1048 static HRESULT WINAPI rowset_RestartPosition(IRowset* iface, HCHAPTER hReserved)
1049 {
1050     rowset_proxy *This = impl_from_IRowset(iface);
1051
1052     FIXME("(%p)->(%lx): stub\n", This, hReserved);
1053
1054     return E_NOTIMPL;
1055 }
1056
1057 static const IRowsetVtbl rowset_vtbl =
1058 {
1059     rowset_QueryInterface,
1060     rowset_AddRef,
1061     rowset_Release,
1062     rowset_AddRefRows,
1063     rowset_GetData,
1064     rowset_GetNextRows,
1065     rowset_ReleaseRows,
1066     rowset_RestartPosition
1067 };
1068
1069 static HRESULT WINAPI rowsetlocate_QueryInterface(IRowsetLocate *iface, REFIID iid, void **obj)
1070 {
1071     rowset_proxy *This = impl_from_IRowsetLocate(iface);
1072     return IUnknown_QueryInterface((IUnknown *)This, iid, obj);
1073 }
1074
1075 static ULONG WINAPI rowsetlocate_AddRef(IRowsetLocate *iface)
1076 {
1077     rowset_proxy *This = impl_from_IRowsetLocate(iface);
1078     return IUnknown_AddRef((IUnknown *)This);
1079 }
1080
1081 static ULONG WINAPI rowsetlocate_Release(IRowsetLocate *iface)
1082 {
1083     rowset_proxy *This = impl_from_IRowsetLocate(iface);
1084     return IUnknown_Release((IUnknown *)This);
1085 }
1086
1087 static HRESULT WINAPI rowsetlocate_AddRefRows(IRowsetLocate *iface, DBCOUNTITEM cRows, const HROW rghRows[],
1088                                               DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[])
1089 {
1090     rowset_proxy *This = impl_from_IRowsetLocate(iface);
1091     return IRowset_AddRefRows((IRowset*)This, cRows, rghRows, rgRefCounts, rgRowStatus);
1092 }
1093
1094 static HRESULT WINAPI rowsetlocate_GetData(IRowsetLocate *iface, HROW hRow, HACCESSOR hAccessor, void *pData)
1095 {
1096     rowset_proxy *This = impl_from_IRowsetLocate(iface);
1097     return IRowset_GetData((IRowset*)This, hRow, hAccessor, pData);
1098 }
1099
1100 static HRESULT WINAPI rowsetlocate_GetNextRows(IRowsetLocate *iface, HCHAPTER hReserved, DBROWOFFSET lRowsOffset,
1101                                                DBROWCOUNT cRows, DBCOUNTITEM *pcRowObtained, HROW **prghRows)
1102 {
1103     rowset_proxy *This = impl_from_IRowsetLocate(iface);
1104     return IRowset_GetNextRows((IRowset*)This, hReserved, lRowsOffset, cRows, pcRowObtained, prghRows);
1105 }
1106
1107 static HRESULT WINAPI rowsetlocate_ReleaseRows(IRowsetLocate *iface, DBCOUNTITEM cRows, const HROW rghRows[],
1108                                                DBROWOPTIONS rgRowOptions[], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[])
1109 {
1110     rowset_proxy *This = impl_from_IRowsetLocate(iface);
1111     return IRowset_ReleaseRows((IRowset*)This, cRows, rghRows, rgRowOptions, rgRefCounts, rgRowStatus);
1112 }
1113
1114 static HRESULT WINAPI rowsetlocate_RestartPosition(IRowsetLocate *iface, HCHAPTER hReserved)
1115 {
1116     rowset_proxy *This = impl_from_IRowsetLocate(iface);
1117     return IRowset_RestartPosition((IRowset*)This, hReserved);
1118 }
1119
1120 static HRESULT WINAPI rowsetlocate_Compare(IRowsetLocate *iface, HCHAPTER hReserved, DBBKMARK cbBookmark1, const BYTE *pBookmark1,
1121                                            DBBKMARK cbBookmark2, const BYTE *pBookmark2, DBCOMPARE *pComparison)
1122 {
1123     rowset_proxy *This = impl_from_IRowsetLocate(iface);
1124     FIXME("(%p)\n", This);
1125     return E_NOTIMPL;
1126 }
1127
1128 static HRESULT WINAPI rowsetlocate_GetRowsAt(IRowsetLocate *iface, HWATCHREGION hReserved1, HCHAPTER hReserved2, DBBKMARK cbBookmark,
1129                                              const BYTE *pBookmark, DBROWOFFSET lRowsOffset, DBROWCOUNT cRows, DBCOUNTITEM *pcRowsObtained,
1130                                              HROW **prghRows)
1131 {
1132     rowset_proxy *This = impl_from_IRowsetLocate(iface);
1133     HRESULT hr;
1134     HROW *rows = NULL;
1135
1136     TRACE("(%p)->(%08lx, %08lx, %d, %p, %d, %d, %p, %p\n", This, hReserved1, hReserved2, cbBookmark, pBookmark, lRowsOffset, cRows,
1137           pcRowsObtained, prghRows);
1138
1139     hr = IWineRowServer_GetRowsAt(This->server, hReserved1, hReserved2, cbBookmark, pBookmark, lRowsOffset, cRows, pcRowsObtained, &rows);
1140
1141     if(*prghRows)
1142     {
1143         memcpy(*prghRows, rows, *pcRowsObtained * sizeof(rows[0]));
1144         CoTaskMemFree(rows);
1145     }
1146     else
1147         *prghRows = rows;
1148
1149     return hr;
1150 }
1151
1152 static HRESULT WINAPI rowsetlocate_GetRowsByBookmark(IRowsetLocate *iface, HCHAPTER hReserved, DBCOUNTITEM cRows, const DBBKMARK rgcbBookmarks[],
1153                                                      const BYTE * rgpBookmarks[], HROW rghRows[], DBROWSTATUS rgRowStatus[])
1154 {
1155     rowset_proxy *This = impl_from_IRowsetLocate(iface);
1156     FIXME("(%p)\n", This);
1157     return E_NOTIMPL;
1158 }
1159
1160 static HRESULT WINAPI rowsetlocate_Hash(IRowsetLocate *iface, HCHAPTER hReserved, DBBKMARK cBookmarks, const DBBKMARK rgcbBookmarks[],
1161                                         const BYTE * rgpBookmarks[], DBHASHVALUE rgHashedValues[], DBROWSTATUS rgBookmarkStatus[])
1162 {
1163     rowset_proxy *This = impl_from_IRowsetLocate(iface);
1164     FIXME("(%p)\n", This);
1165     return E_NOTIMPL;
1166 }
1167
1168 static const IRowsetLocateVtbl rowsetlocate_vtbl =
1169 {
1170     rowsetlocate_QueryInterface,
1171     rowsetlocate_AddRef,
1172     rowsetlocate_Release,
1173     rowsetlocate_AddRefRows,
1174     rowsetlocate_GetData,
1175     rowsetlocate_GetNextRows,
1176     rowsetlocate_ReleaseRows,
1177     rowsetlocate_RestartPosition,
1178     rowsetlocate_Compare,
1179     rowsetlocate_GetRowsAt,
1180     rowsetlocate_GetRowsByBookmark,
1181     rowsetlocate_Hash
1182 };
1183
1184 static HRESULT WINAPI rowsetinfo_QueryInterface(IRowsetInfo *iface, REFIID iid, void **obj)
1185 {
1186     rowset_proxy *This = impl_from_IRowsetInfo(iface);
1187     return IUnknown_QueryInterface((IUnknown *)This, iid, obj);
1188 }
1189
1190 static ULONG WINAPI rowsetinfo_AddRef(IRowsetInfo *iface)
1191 {
1192     rowset_proxy *This = impl_from_IRowsetInfo(iface);
1193     return IUnknown_AddRef((IUnknown *)This);
1194 }
1195
1196 static ULONG WINAPI rowsetinfo_Release(IRowsetInfo *iface)
1197 {
1198     rowset_proxy *This = impl_from_IRowsetInfo(iface);
1199     return IUnknown_Release((IUnknown *)This);
1200 }
1201
1202 static HRESULT WINAPI rowsetinfo_GetProperties(IRowsetInfo *iface, const ULONG cPropertyIDSets,
1203                                                const DBPROPIDSET rgPropertyIDSets[], ULONG *pcPropertySets,
1204                                                DBPROPSET **prgPropertySets)
1205 {
1206     rowset_proxy *This = impl_from_IRowsetInfo(iface);
1207     HRESULT hr;
1208
1209     TRACE("(%p)->(%d, %p, %p, %p)\n", This, cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
1210
1211     hr = IWineRowServer_GetProperties(This->server, cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
1212
1213     return hr;
1214 }
1215
1216 static HRESULT WINAPI rowsetinfo_GetReferencedRowset(IRowsetInfo *iface, DBORDINAL iOrdinal, REFIID riid,
1217                                                      IUnknown **ppReferencedRowset)
1218 {
1219     rowset_proxy *This = impl_from_IRowsetInfo(iface);
1220     FIXME("(%p)\n", This);
1221     return E_NOTIMPL;
1222 }
1223
1224 static HRESULT WINAPI rowsetinfo_GetSpecification(IRowsetInfo *iface, REFIID riid, IUnknown **ppSpecification)
1225 {
1226     rowset_proxy *This = impl_from_IRowsetInfo(iface);
1227     FIXME("(%p)\n", This);
1228     return E_NOTIMPL;
1229 }
1230
1231 static const IRowsetInfoVtbl rowsetinfo_vtbl =
1232 {
1233     rowsetinfo_QueryInterface,
1234     rowsetinfo_AddRef,
1235     rowsetinfo_Release,
1236     rowsetinfo_GetProperties,
1237     rowsetinfo_GetReferencedRowset,
1238     rowsetinfo_GetSpecification
1239 };
1240
1241 static HRESULT WINAPI accessor_QueryInterface(IAccessor *iface, REFIID iid, void **obj)
1242 {
1243     rowset_proxy *This = impl_from_IAccessor(iface);
1244     return IUnknown_QueryInterface((IUnknown *)This, iid, obj);
1245 }
1246
1247 static ULONG WINAPI accessor_AddRef(IAccessor *iface)
1248 {
1249     rowset_proxy *This = impl_from_IAccessor(iface);
1250     return IUnknown_AddRef((IUnknown *)This);
1251 }
1252
1253 static ULONG WINAPI accessor_Release(IAccessor *iface)
1254 {
1255     rowset_proxy *This = impl_from_IAccessor(iface);
1256     return IUnknown_Release((IUnknown *)This);
1257 }
1258
1259 static HRESULT WINAPI accessor_AddRefAccessor(IAccessor *iface, HACCESSOR hAccessor, DBREFCOUNT *pcRefCount)
1260 {
1261     rowset_proxy *This = impl_from_IAccessor(iface);
1262     FIXME("(%p)\n", This);
1263     return E_NOTIMPL;
1264 }
1265
1266 static HRESULT WINAPI accessor_CreateAccessor(IAccessor *iface, DBACCESSORFLAGS dwAccessorFlags, DBCOUNTITEM cBindings,
1267                                               const DBBINDING rgBindings[], DBLENGTH cbRowSize, HACCESSOR *phAccessor,
1268                                               DBBINDSTATUS rgStatus[])
1269 {
1270     rowset_proxy *This = impl_from_IAccessor(iface);
1271     HRESULT hr;
1272     DBBINDSTATUS *status;
1273
1274     TRACE("(%p)->(%08x, %d, %p, %d, %p, %p)\n", This, dwAccessorFlags, cBindings, rgBindings, cbRowSize, phAccessor, rgStatus);
1275
1276     if(!rgStatus) status = CoTaskMemAlloc(cBindings * sizeof(status[0]));
1277     else status = rgStatus;
1278
1279     hr = IWineRowServer_CreateAccessor(This->server, dwAccessorFlags, cBindings, rgBindings, cbRowSize, phAccessor, status);
1280
1281     if(!rgStatus) CoTaskMemFree(status);
1282
1283     return hr;
1284 }
1285
1286 static HRESULT WINAPI accessor_GetBindings(IAccessor *iface, HACCESSOR hAccessor, DBACCESSORFLAGS *pdwAccessorFlags,
1287                                            DBCOUNTITEM *pcBindings, DBBINDING **prgBindings)
1288 {
1289     rowset_proxy *This = impl_from_IAccessor(iface);
1290     HRESULT hr;
1291
1292     TRACE("(%p)->(%08lx, %p, %p, %p)\n", This, hAccessor, pdwAccessorFlags, pcBindings, prgBindings);
1293
1294     hr = IWineRowServer_GetBindings(This->server, hAccessor, pdwAccessorFlags, pcBindings, prgBindings);
1295
1296     return hr;
1297 }
1298
1299 static HRESULT WINAPI accessor_ReleaseAccessor(IAccessor *iface, HACCESSOR hAccessor, DBREFCOUNT *pcRefCount)
1300 {
1301     rowset_proxy *This = impl_from_IAccessor(iface);
1302     HRESULT hr;
1303     DBREFCOUNT ref;
1304
1305     TRACE("(%p)->(%08lx, %p)\n", This, hAccessor, pcRefCount);
1306
1307     hr = IWineRowServer_ReleaseAccessor(This->server, hAccessor, &ref);
1308     if(pcRefCount) *pcRefCount = ref;
1309     return hr;
1310 }
1311
1312 static const IAccessorVtbl accessor_vtbl =
1313 {
1314     accessor_QueryInterface,
1315     accessor_AddRef,
1316     accessor_Release,
1317     accessor_AddRefAccessor,
1318     accessor_CreateAccessor,
1319     accessor_GetBindings,
1320     accessor_ReleaseAccessor
1321 };
1322
1323 HRESULT create_rowset_proxy(IWineRowServer *server, IUnknown **obj)
1324 {
1325     rowset_proxy *proxy;
1326
1327     TRACE("(%p, %p)\n", server, obj);
1328     *obj = NULL;
1329
1330     proxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*proxy));
1331     if(!proxy) return E_OUTOFMEMORY;
1332
1333     proxy->rowset_vtbl = &rowset_vtbl;
1334     proxy->rowsetlocate_vtbl = &rowsetlocate_vtbl;
1335     proxy->rowsetinfo_vtbl = &rowsetinfo_vtbl;
1336     proxy->accessor_vtbl = &accessor_vtbl;
1337     proxy->ref = 1;
1338     IWineRowServer_AddRef(server);
1339     proxy->server = server;
1340
1341     *obj = (IUnknown *)&proxy->rowset_vtbl;
1342     TRACE("returning %p\n", *obj);
1343     return S_OK;
1344 }
1345
1346 static HRESULT create_proxy(IWineRowServer *server, const CLSID *class, IUnknown **obj)
1347 {
1348     *obj = NULL;
1349
1350     if(IsEqualGUID(class, &CLSID_wine_row_proxy))
1351         return create_row_proxy(server, obj);
1352     else if(IsEqualGUID(class, &CLSID_wine_rowset_proxy))
1353         return create_rowset_proxy(server, obj);
1354     else
1355         FIXME("Unhandled proxy class %s\n", debugstr_guid(class));
1356     return E_NOTIMPL;
1357 }
1358
1359 /* Marshal impl */
1360
1361 typedef struct
1362 {
1363     const IMarshalVtbl *marshal_vtbl;
1364
1365     LONG ref;
1366     CLSID unmarshal_class;
1367     IUnknown *outer;
1368 } marshal;
1369
1370 static inline marshal *impl_from_IMarshal(IMarshal *iface)
1371 {
1372     return (marshal *)((char*)iface - FIELD_OFFSET(marshal, marshal_vtbl));
1373 }
1374
1375 static HRESULT WINAPI marshal_QueryInterface(IMarshal *iface, REFIID iid, void **obj)
1376 {
1377     marshal *This = impl_from_IMarshal(iface);
1378     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(iid), obj);
1379
1380     if(IsEqualIID(iid, &IID_IUnknown) ||
1381        IsEqualIID(iid, &IID_IMarshal))
1382     {
1383         *obj = iface;
1384     }
1385     else
1386     {
1387         FIXME("interface %s not implemented\n", debugstr_guid(iid));
1388         *obj = NULL;
1389         return E_NOINTERFACE;
1390     }
1391
1392     IMarshal_AddRef(iface);
1393     return S_OK;
1394 }
1395
1396 static ULONG WINAPI marshal_AddRef(IMarshal *iface)
1397 {
1398     marshal *This = impl_from_IMarshal(iface);
1399     TRACE("(%p)\n", This);
1400     return InterlockedIncrement(&This->ref);
1401 }
1402
1403 static ULONG WINAPI marshal_Release(IMarshal *iface)
1404 {
1405     marshal *This = impl_from_IMarshal(iface);
1406     LONG ref;
1407
1408     TRACE("(%p)\n", This);
1409
1410     ref = InterlockedDecrement(&This->ref);
1411     if(ref == 0)
1412     {
1413         HeapFree(GetProcessHeap(), 0, This);
1414     }
1415
1416     return ref;
1417 }
1418
1419 static HRESULT WINAPI marshal_GetUnmarshalClass(IMarshal *iface, REFIID iid, void *obj,
1420                                                 DWORD dwDestContext, void *pvDestContext,
1421                                                 DWORD mshlflags, CLSID *clsid)
1422 {
1423     marshal *This = impl_from_IMarshal(iface);
1424     TRACE("(%p)->(%s, %p, %08x, %p, %08x, %p)\n", This, debugstr_guid(iid), obj, dwDestContext,
1425           pvDestContext, mshlflags, clsid);
1426
1427     *clsid = This->unmarshal_class;
1428     return S_OK;
1429 }
1430
1431 static HRESULT WINAPI marshal_GetMarshalSizeMax(IMarshal *iface, REFIID iid, void *obj,
1432                                                 DWORD dwDestContext, void *pvDestContext,
1433                                                 DWORD mshlflags, DWORD *size)
1434 {
1435     marshal *This = impl_from_IMarshal(iface);
1436     TRACE("(%p)->(%s, %p, %08x, %p, %08x, %p)\n", This, debugstr_guid(iid), obj, dwDestContext,
1437           pvDestContext, mshlflags, size);
1438
1439     return CoGetMarshalSizeMax(size, &IID_IWineRowServer, This->outer, dwDestContext, pvDestContext,
1440                                mshlflags);
1441 }
1442
1443 static HRESULT WINAPI marshal_MarshalInterface(IMarshal *iface, IStream *stream, REFIID iid,
1444                                                void *obj, DWORD dwDestContext, void *pvDestContext,
1445                                                DWORD mshlflags)
1446 {
1447     marshal *This = impl_from_IMarshal(iface);
1448     TRACE("(%p)->(%p, %s, %p, %08x, %p, %08x)\n", This, stream, debugstr_guid(iid), obj, dwDestContext,
1449           pvDestContext, mshlflags);
1450
1451     return CoMarshalInterface(stream, &IID_IWineRowServer, This->outer, dwDestContext, pvDestContext, mshlflags);
1452 }
1453
1454 static HRESULT WINAPI marshal_UnmarshalInterface(IMarshal *iface, IStream *stream,
1455                                                  REFIID iid, void **obj)
1456 {
1457     marshal *This = impl_from_IMarshal(iface);
1458     HRESULT hr;
1459     IWineRowServer *server;
1460     IUnknown *proxy;
1461
1462     TRACE("(%p)->(%p, %s, %p)\n", This, stream, debugstr_guid(iid), obj);
1463     *obj = NULL;
1464
1465     hr = CoUnmarshalInterface(stream, &IID_IWineRowServer, (void**)&server);
1466     if(SUCCEEDED(hr))
1467     {
1468         hr = create_proxy(server, &This->unmarshal_class, &proxy);
1469         if(SUCCEEDED(hr))
1470         {
1471             hr = IUnknown_QueryInterface(proxy, iid, obj);
1472             IUnknown_Release(proxy);
1473         }
1474         IWineRowServer_Release(server);
1475     }
1476
1477     TRACE("returning %p\n", *obj);
1478     return hr;
1479 }
1480
1481 static HRESULT WINAPI marshal_ReleaseMarshalData(IMarshal *iface, IStream *stream)
1482 {
1483     marshal *This = impl_from_IMarshal(iface);
1484     TRACE("(%p)->(%p)\n", This, stream);
1485     return CoReleaseMarshalData(stream);
1486 }
1487
1488 static HRESULT WINAPI marshal_DisconnectObject(IMarshal *iface, DWORD dwReserved)
1489 {
1490     marshal *This = impl_from_IMarshal(iface);
1491     FIXME("(%p)->(%08x)\n", This, dwReserved);
1492
1493     return E_NOTIMPL;
1494 }
1495
1496 static const IMarshalVtbl marshal_vtbl =
1497 {
1498     marshal_QueryInterface,
1499     marshal_AddRef,
1500     marshal_Release,
1501     marshal_GetUnmarshalClass,
1502     marshal_GetMarshalSizeMax,
1503     marshal_MarshalInterface,
1504     marshal_UnmarshalInterface,
1505     marshal_ReleaseMarshalData,
1506     marshal_DisconnectObject
1507 };
1508
1509 static HRESULT create_marshal(IUnknown *outer, const CLSID *class, void **obj)
1510 {
1511     marshal *marshal;
1512
1513     TRACE("(%p, %p)\n", outer, obj);
1514     *obj = NULL;
1515
1516     marshal = HeapAlloc(GetProcessHeap(), 0, sizeof(*marshal));
1517     if(!marshal) return E_OUTOFMEMORY;
1518
1519     marshal->unmarshal_class = *class;
1520     marshal->outer = outer; /* don't ref outer unk */
1521     marshal->marshal_vtbl = &marshal_vtbl;
1522     marshal->ref = 1;
1523
1524     *obj = &marshal->marshal_vtbl;
1525     TRACE("returning %p\n", *obj);
1526     return S_OK;
1527 }
1528
1529 HRESULT create_row_marshal(IUnknown *outer, void **obj)
1530 {
1531     TRACE("(%p, %p)\n", outer, obj);
1532     return create_marshal(outer, &CLSID_wine_row_proxy, obj);
1533 }
1534
1535 HRESULT create_rowset_marshal(IUnknown *outer, void **obj)
1536 {
1537     TRACE("(%p, %p)\n", outer, obj);
1538     return create_marshal(outer, &CLSID_wine_rowset_proxy, obj);
1539 }