blob: bc0f6526fded402b93d5299aa9b83e90baf2d0af [file] [log] [blame]
Huw Daviesde6f3812010-01-21 11:53:25 +00001/*
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
40WINE_DEFAULT_DEBUG_CHANNEL(oledb);
41
Huw Davies83eb7792010-02-03 11:48:21 +000042static 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}
Huw Daviesd1dfdd72010-02-02 12:07:12 +000075
76typedef struct
77{
78 const IWineRowServerVtbl *vtbl;
79
80 LONG ref;
81
82 CLSID class;
83 IMarshal *marshal;
84 IUnknown *inner_unk;
85} server;
86
87static inline server *impl_from_IWineRowServer(IWineRowServer *iface)
88{
89 return (server *)((char*)iface - FIELD_OFFSET(server, vtbl));
90}
91
92static 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
115static 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
123static 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
141static 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
152static 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
Huw Davies83eb7792010-02-03 11:48:21 +0000161static 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
209static 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
217static 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);
Huw Daviesd3f81a92010-02-04 19:54:59 +0000222 IRow *row;
223 HRESULT hr;
224 IWineRowServer *new_server;
225 IMarshal *marshal;
226 IUnknown *obj;
Huw Davies83eb7792010-02-03 11:48:21 +0000227
Huw Daviesd3f81a92010-02-04 19:54:59 +0000228 TRACE("(%p)->(%p, %p, %s, %08x, %s, %p)\n", This, pUnkOuter, pColumnID, debugstr_guid(rguidColumnType),
Huw Davies83eb7792010-02-03 11:48:21 +0000229 dwBindFlags, debugstr_guid(riid), ppUnk);
Huw Daviesd3f81a92010-02-04 19:54:59 +0000230
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;
Huw Davies83eb7792010-02-03 11:48:21 +0000267}
268
Huw Daviesb2769db2010-02-04 11:43:38 +0000269static 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);
Huw Davies559a7c82010-02-05 13:29:32 +0000273 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;
Huw Daviesb2769db2010-02-04 11:43:38 +0000310}
311
312static 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);
Huw Daviesa7001bd2010-02-04 11:48:02 +0000317 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;
Huw Daviesb2769db2010-02-04 11:43:38 +0000330}
331
332static HRESULT WINAPI server_GetData(IWineRowServer* iface, HROW hRow,
333 HACCESSOR hAccessor, BYTE *pData, DWORD size)
334{
335 server *This = impl_from_IWineRowServer(iface);
Huw Davies8c5f4f02010-02-04 14:34:17 +0000336 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;
Huw Daviesb2769db2010-02-04 11:43:38 +0000349}
350
351static 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);
Huw Davies93ea2e02010-02-04 11:52:52 +0000355 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;
Huw Daviesb2769db2010-02-04 11:43:38 +0000369}
370
371static 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);
Huw Daviese44206d2010-02-04 11:55:36 +0000375 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;
Huw Daviesb2769db2010-02-04 11:43:38 +0000388}
389
390static 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
Huw Davies923805b2010-02-04 12:07:08 +0000397static 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
406static 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);
Huw Davies0ea00792010-02-04 14:47:56 +0000411 IRowsetLocate *rowsetlocate;
412 HRESULT hr;
Huw Davies923805b2010-02-04 12:07:08 +0000413
Huw Davies0ea00792010-02-04 14:47:56 +0000414 TRACE("(%p)->(%08lx, %08lx, %d, %p, %d, %d, %p, %p\n", This, hReserved1, hReserved2, cbBookmark, pBookmark, lRowsOffset, cRows,
415 pcRowsObtained, prghRows);
Huw Davies923805b2010-02-04 12:07:08 +0000416
Huw Davies0ea00792010-02-04 14:47:56 +0000417 *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;
Huw Davies923805b2010-02-04 12:07:08 +0000428}
429
430static 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
439static 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
Huw Davies59c2caa2010-02-04 12:12:35 +0000448static 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);
Huw Daviesa437cc22010-02-04 14:21:30 +0000453 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;
Huw Davies59c2caa2010-02-04 12:12:35 +0000466}
467
468static 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
476static 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
Huw Davies7deb07c2010-02-04 12:19:06 +0000484static 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
492static 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);
Huw Davies95c94172010-02-04 14:07:25 +0000497 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;
Huw Davies7deb07c2010-02-04 12:19:06 +0000510}
511
512static HRESULT WINAPI server_GetBindings(IWineRowServer* iface, HACCESSOR hAccessor,
513 DBACCESSORFLAGS *pdwAccessorFlags, DBCOUNTITEM *pcBindings,
514 DBBINDING **prgBindings)
515{
516 server *This = impl_from_IWineRowServer(iface);
Huw Daviesef32e862010-02-04 14:13:17 +0000517 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;
Huw Davies7deb07c2010-02-04 12:19:06 +0000530}
531
532static HRESULT WINAPI server_ReleaseAccessor(IWineRowServer* iface, HACCESSOR hAccessor,
533 DBREFCOUNT *pcRefCount)
534{
535 server *This = impl_from_IWineRowServer(iface);
Huw Davies5a407112010-02-04 14:10:08 +0000536 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;
Huw Davies7deb07c2010-02-04 12:19:06 +0000548}
549
Huw Daviesd1dfdd72010-02-02 12:07:12 +0000550static const IWineRowServerVtbl server_vtbl =
551{
552 server_QueryInterface,
553 server_AddRef,
554 server_Release,
555 server_SetInnerUnk,
Huw Davies83eb7792010-02-03 11:48:21 +0000556 server_GetMarshal,
557 server_GetColumns,
558 server_GetSourceRowset,
Huw Daviesb2769db2010-02-04 11:43:38 +0000559 server_Open,
560 server_SetColumns,
561 server_AddRefRows,
562 server_GetData,
563 server_GetNextRows,
564 server_ReleaseRows,
Huw Davies923805b2010-02-04 12:07:08 +0000565 server_RestartPosition,
566 server_Compare,
567 server_GetRowsAt,
568 server_GetRowsByBookmark,
Huw Davies59c2caa2010-02-04 12:12:35 +0000569 server_Hash,
570 server_GetProperties,
571 server_GetReferencedRowset,
Huw Davies7deb07c2010-02-04 12:19:06 +0000572 server_GetSpecification,
573 server_AddRefAccessor,
574 server_CreateAccessor,
575 server_GetBindings,
576 server_ReleaseAccessor
Huw Daviesd1dfdd72010-02-02 12:07:12 +0000577};
578
579static 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
Huw Daviesde6f3812010-01-21 11:53:25 +0000604HRESULT create_row_server(IUnknown *outer, void **obj)
605{
Huw Daviesd1dfdd72010-02-02 12:07:12 +0000606 return create_server(outer, &CLSID_wine_row_server, obj);
Huw Daviesde6f3812010-01-21 11:53:25 +0000607}
608
609HRESULT create_rowset_server(IUnknown *outer, void **obj)
610{
Huw Daviesd1dfdd72010-02-02 12:07:12 +0000611 return create_server(outer, &CLSID_wine_rowset_server, obj);
Huw Daviesde6f3812010-01-21 11:53:25 +0000612}
613
Huw Davies53ecb952010-02-02 16:35:43 +0000614typedef struct
Huw Davies3cd0fde2010-02-02 13:36:25 +0000615{
Huw Davies53ecb952010-02-02 16:35:43 +0000616 const IRowVtbl *row_vtbl;
Huw Daviesb2769db2010-02-04 11:43:38 +0000617 const IRowChangeVtbl *row_change_vtbl;
Huw Davies53ecb952010-02-02 16:35:43 +0000618
619 LONG ref;
620
621 IWineRowServer *server;
622} row_proxy;
623
624static inline row_proxy *impl_from_IRow(IRow *iface)
625{
626 return (row_proxy *)((char*)iface - FIELD_OFFSET(row_proxy, row_vtbl));
627}
628
Huw Daviesb2769db2010-02-04 11:43:38 +0000629static inline row_proxy *impl_from_IRowChange(IRowChange *iface)
630{
631 return (row_proxy *)((char*)iface - FIELD_OFFSET(row_proxy, row_change_vtbl));
632}
633
Huw Davies53ecb952010-02-02 16:35:43 +0000634static 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 }
Huw Daviesb2769db2010-02-04 11:43:38 +0000644 else if(IsEqualIID(iid, &IID_IRowChange))
645 {
646 *obj = &This->row_change_vtbl;
647 }
Huw Davies53ecb952010-02-02 16:35:43 +0000648 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
658static 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
666static 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
683static HRESULT WINAPI row_GetColumns(IRow* iface, DBORDINAL cColumns, DBCOLUMNACCESS rgColumns[])
684{
685 row_proxy *This = impl_from_IRow(iface);
Huw Davies83eb7792010-02-03 11:48:21 +0000686 DBORDINAL i;
687 wine_getcolumns_in *in_data;
688 wine_getcolumns_out *out_data;
689 HRESULT hr;
Huw Davies53ecb952010-02-02 16:35:43 +0000690
Huw Davies83eb7792010-02-03 11:48:21 +0000691 TRACE("(%p)->(%d, %p)\n", This, cColumns, rgColumns);
Huw Davies53ecb952010-02-02 16:35:43 +0000692
Huw Davies83eb7792010-02-03 11:48:21 +0000693 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;
Huw Davies53ecb952010-02-02 16:35:43 +0000720}
721
722static 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
732static 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
Huw Daviesd3f81a92010-02-04 19:54:59 +0000738 TRACE("(%p)->(%p, %p, %s, %08x, %s, %p)\n", This, pUnkOuter, pColumnID, debugstr_guid(rguidColumnType),
Huw Davies53ecb952010-02-02 16:35:43 +0000739 dwBindFlags, debugstr_guid(riid), ppUnk);
Huw Daviesd3f81a92010-02-04 19:54:59 +0000740 if(pUnkOuter)
741 {
742 FIXME("Aggregation not supported\n");
743 return CLASS_E_NOAGGREGATION;
744 }
Huw Davies53ecb952010-02-02 16:35:43 +0000745
Huw Daviesd3f81a92010-02-04 19:54:59 +0000746 return IWineRowServer_Open(This->server, pUnkOuter, pColumnID, rguidColumnType, dwBindFlags, riid, ppUnk);
Huw Davies53ecb952010-02-02 16:35:43 +0000747}
748
749static 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
Huw Daviesb2769db2010-02-04 11:43:38 +0000759static 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
765static ULONG WINAPI row_change_AddRef(IRowChange *iface)
766{
767 row_proxy *This = impl_from_IRowChange(iface);
768 return IUnknown_AddRef((IUnknown*)This);
769}
770
771static ULONG WINAPI row_change_Release(IRowChange *iface)
772{
773 row_proxy *This = impl_from_IRowChange(iface);
774 return IUnknown_Release((IUnknown*)This);
775}
776
777static HRESULT WINAPI row_change_SetColumns(IRowChange *iface, DBORDINAL cColumns,
778 DBCOLUMNACCESS rgColumns[])
779{
780 row_proxy *This = impl_from_IRowChange(iface);
Huw Davies559a7c82010-02-05 13:29:32 +0000781 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;
Huw Daviesb2769db2010-02-04 11:43:38 +0000814}
815
816static const IRowChangeVtbl row_change_vtbl =
817{
818 row_change_QueryInterface,
819 row_change_AddRef,
820 row_change_Release,
821 row_change_SetColumns
822};
823
Huw Davies53ecb952010-02-02 16:35:43 +0000824static HRESULT create_row_proxy(IWineRowServer *server, IUnknown **obj)
825{
826 row_proxy *proxy;
827
828 TRACE("(%p, %p)\n", server, obj);
Huw Davies3cd0fde2010-02-02 13:36:25 +0000829 *obj = NULL;
Huw Davies53ecb952010-02-02 16:35:43 +0000830
831 proxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*proxy));
832 if(!proxy) return E_OUTOFMEMORY;
833
834 proxy->row_vtbl = &row_vtbl;
Huw Daviesb2769db2010-02-04 11:43:38 +0000835 proxy->row_change_vtbl = &row_change_vtbl;
Huw Davies53ecb952010-02-02 16:35:43 +0000836 proxy->ref = 1;
837 IWineRowServer_AddRef(server);
838 proxy->server = server;
839
840 *obj = (IUnknown*)&proxy->row_vtbl;
Francois Gouget3428b942010-03-20 15:24:53 +0100841 TRACE("returning %p\n", *obj);
Huw Davies53ecb952010-02-02 16:35:43 +0000842 return S_OK;
843}
844
Huw Davies92c88612010-02-02 16:49:47 +0000845typedef struct
846{
847 const IRowsetVtbl *rowset_vtbl;
Huw Davies7cbf1642010-02-04 12:33:06 +0000848 const IRowsetLocateVtbl *rowsetlocate_vtbl;
849 const IRowsetInfoVtbl *rowsetinfo_vtbl;
850 const IAccessorVtbl *accessor_vtbl;
Huw Davies92c88612010-02-02 16:49:47 +0000851
852 LONG ref;
853
854 IWineRowServer *server;
855} rowset_proxy;
856
857static inline rowset_proxy *impl_from_IRowset(IRowset *iface)
858{
859 return (rowset_proxy *)((char*)iface - FIELD_OFFSET(rowset_proxy, rowset_vtbl));
860}
861
Huw Davies7cbf1642010-02-04 12:33:06 +0000862static inline rowset_proxy *impl_from_IRowsetLocate(IRowsetLocate *iface)
863{
864 return (rowset_proxy *)((char*)iface - FIELD_OFFSET(rowset_proxy, rowsetlocate_vtbl));
865}
866
867static inline rowset_proxy *impl_from_IRowsetInfo(IRowsetInfo *iface)
868{
869 return (rowset_proxy *)((char*)iface - FIELD_OFFSET(rowset_proxy, rowsetinfo_vtbl));
870}
871
872static inline rowset_proxy *impl_from_IAccessor(IAccessor *iface)
873{
874 return (rowset_proxy *)((char*)iface - FIELD_OFFSET(rowset_proxy, accessor_vtbl));
875}
876
Huw Davies92c88612010-02-02 16:49:47 +0000877static 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 }
Huw Davies7cbf1642010-02-04 12:33:06 +0000889 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 }
Huw Davies92c88612010-02-02 16:49:47 +0000901 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
911static 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
919static 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
936static 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);
Huw Daviesa7001bd2010-02-04 11:48:02 +0000940 HRESULT hr;
941 DBREFCOUNT *refs = rgRefCounts;
942 DBSTATUS *stats = rgRowStatus;
Huw Davies92c88612010-02-02 16:49:47 +0000943
Huw Daviesa7001bd2010-02-04 11:48:02 +0000944 TRACE("(%p)->(%d, %p, %p, %p)\n", This, cRows, rghRows, rgRefCounts, rgRowStatus);
Huw Davies92c88612010-02-02 16:49:47 +0000945
Huw Daviesa7001bd2010-02-04 11:48:02 +0000946 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;
Huw Davies92c88612010-02-02 16:49:47 +0000955}
956
957static HRESULT WINAPI rowset_GetData(IRowset *iface, HROW hRow, HACCESSOR hAccessor, void *pData)
958{
959 rowset_proxy *This = impl_from_IRowset(iface);
Huw Davies8c5f4f02010-02-04 14:34:17 +0000960 HRESULT hr;
961 IAccessor *accessor;
962 DBACCESSORFLAGS flags;
963 DBCOUNTITEM count, i;
964 DBBINDING *bindings;
965 DWORD max_len = 0;
Huw Davies92c88612010-02-02 16:49:47 +0000966
Huw Davies8c5f4f02010-02-04 14:34:17 +0000967 TRACE("(%p)->(%lx, %lx, %p)\n", This, hRow, hAccessor, pData);
Huw Davies92c88612010-02-02 16:49:47 +0000968
Huw Davies8c5f4f02010-02-04 14:34:17 +0000969 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;
Huw Davies92c88612010-02-02 16:49:47 +0000997}
998
999static 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);
Huw Davies93ea2e02010-02-04 11:52:52 +00001003 HRESULT hr;
1004 HROW *rows = NULL;
Huw Davies92c88612010-02-02 16:49:47 +00001005
Huw Davies93ea2e02010-02-04 11:52:52 +00001006 TRACE("(%p)->(%08lx, %d, %d, %p, %p)\n", This, hReserved, lRowsOffset, cRows, pcRowObtained, prghRows);
Huw Davies92c88612010-02-02 16:49:47 +00001007
Huw Davies93ea2e02010-02-04 11:52:52 +00001008 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;
Huw Davies92c88612010-02-02 16:49:47 +00001018}
1019
1020static 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);
Huw Daviese44206d2010-02-04 11:55:36 +00001024 HRESULT hr;
1025 DBROWOPTIONS *options = rgRowOptions;
1026 DBREFCOUNT *refs = rgRefCounts;
1027 DBROWSTATUS *status = rgRowStatus;
Huw Davies92c88612010-02-02 16:49:47 +00001028
Huw Daviese44206d2010-02-04 11:55:36 +00001029 TRACE("(%p)->(%d, %p, %p, %p, %p)\n", This, cRows, rghRows, rgRowOptions, rgRefCounts, rgRowStatus);
Huw Davies92c88612010-02-02 16:49:47 +00001030
Huw Daviese44206d2010-02-04 11:55:36 +00001031 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;
Huw Davies92c88612010-02-02 16:49:47 +00001046}
1047
1048static 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
1057static 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
Huw Davies7cbf1642010-02-04 12:33:06 +00001069static 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
1075static ULONG WINAPI rowsetlocate_AddRef(IRowsetLocate *iface)
1076{
1077 rowset_proxy *This = impl_from_IRowsetLocate(iface);
1078 return IUnknown_AddRef((IUnknown *)This);
1079}
1080
1081static ULONG WINAPI rowsetlocate_Release(IRowsetLocate *iface)
1082{
1083 rowset_proxy *This = impl_from_IRowsetLocate(iface);
1084 return IUnknown_Release((IUnknown *)This);
1085}
1086
1087static 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
1094static 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
1100static 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
1107static 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
1114static 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
1120static 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
1128static 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);
Huw Davies0ea00792010-02-04 14:47:56 +00001133 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;
Huw Davies7cbf1642010-02-04 12:33:06 +00001150}
1151
1152static 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
1160static 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
1168static 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
1184static 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
1190static ULONG WINAPI rowsetinfo_AddRef(IRowsetInfo *iface)
1191{
1192 rowset_proxy *This = impl_from_IRowsetInfo(iface);
1193 return IUnknown_AddRef((IUnknown *)This);
1194}
1195
1196static ULONG WINAPI rowsetinfo_Release(IRowsetInfo *iface)
1197{
1198 rowset_proxy *This = impl_from_IRowsetInfo(iface);
1199 return IUnknown_Release((IUnknown *)This);
1200}
1201
1202static 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);
Huw Daviesa437cc22010-02-04 14:21:30 +00001207 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;
Huw Davies7cbf1642010-02-04 12:33:06 +00001214}
1215
1216static 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
1224static 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
1231static 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
1241static 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
1247static ULONG WINAPI accessor_AddRef(IAccessor *iface)
1248{
1249 rowset_proxy *This = impl_from_IAccessor(iface);
1250 return IUnknown_AddRef((IUnknown *)This);
1251}
1252
1253static ULONG WINAPI accessor_Release(IAccessor *iface)
1254{
1255 rowset_proxy *This = impl_from_IAccessor(iface);
1256 return IUnknown_Release((IUnknown *)This);
1257}
1258
1259static 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
1266static 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);
Huw Davies95c94172010-02-04 14:07:25 +00001271 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;
Huw Davies7cbf1642010-02-04 12:33:06 +00001284}
1285
1286static HRESULT WINAPI accessor_GetBindings(IAccessor *iface, HACCESSOR hAccessor, DBACCESSORFLAGS *pdwAccessorFlags,
1287 DBCOUNTITEM *pcBindings, DBBINDING **prgBindings)
1288{
1289 rowset_proxy *This = impl_from_IAccessor(iface);
Huw Daviesef32e862010-02-04 14:13:17 +00001290 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;
Huw Davies7cbf1642010-02-04 12:33:06 +00001297}
1298
1299static HRESULT WINAPI accessor_ReleaseAccessor(IAccessor *iface, HACCESSOR hAccessor, DBREFCOUNT *pcRefCount)
1300{
1301 rowset_proxy *This = impl_from_IAccessor(iface);
Huw Davies5a407112010-02-04 14:10:08 +00001302 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;
Huw Davies7cbf1642010-02-04 12:33:06 +00001310}
1311
1312static 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
Francois Gouget1aa51f52010-08-24 10:01:10 +02001323static HRESULT create_rowset_proxy(IWineRowServer *server, IUnknown **obj)
Huw Davies92c88612010-02-02 16:49:47 +00001324{
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;
Huw Davies7cbf1642010-02-04 12:33:06 +00001334 proxy->rowsetlocate_vtbl = &rowsetlocate_vtbl;
1335 proxy->rowsetinfo_vtbl = &rowsetinfo_vtbl;
1336 proxy->accessor_vtbl = &accessor_vtbl;
Huw Davies92c88612010-02-02 16:49:47 +00001337 proxy->ref = 1;
1338 IWineRowServer_AddRef(server);
1339 proxy->server = server;
1340
1341 *obj = (IUnknown *)&proxy->rowset_vtbl;
Francois Gouget3428b942010-03-20 15:24:53 +01001342 TRACE("returning %p\n", *obj);
Huw Davies92c88612010-02-02 16:49:47 +00001343 return S_OK;
1344}
1345
Huw Davies53ecb952010-02-02 16:35:43 +00001346static 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);
Huw Davies92c88612010-02-02 16:49:47 +00001352 else if(IsEqualGUID(class, &CLSID_wine_rowset_proxy))
1353 return create_rowset_proxy(server, obj);
Huw Davies53ecb952010-02-02 16:35:43 +00001354 else
1355 FIXME("Unhandled proxy class %s\n", debugstr_guid(class));
Huw Davies3cd0fde2010-02-02 13:36:25 +00001356 return E_NOTIMPL;
1357}
1358
Huw Davies39710f82010-02-02 11:52:51 +00001359/* Marshal impl */
1360
1361typedef struct
1362{
1363 const IMarshalVtbl *marshal_vtbl;
1364
1365 LONG ref;
1366 CLSID unmarshal_class;
1367 IUnknown *outer;
1368} marshal;
1369
1370static inline marshal *impl_from_IMarshal(IMarshal *iface)
1371{
1372 return (marshal *)((char*)iface - FIELD_OFFSET(marshal, marshal_vtbl));
1373}
1374
1375static 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
1396static 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
1403static 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
1419static 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);
Huw Davies3cd0fde2010-02-02 13:36:25 +00001424 TRACE("(%p)->(%s, %p, %08x, %p, %08x, %p)\n", This, debugstr_guid(iid), obj, dwDestContext,
Huw Davies39710f82010-02-02 11:52:51 +00001425 pvDestContext, mshlflags, clsid);
1426
Huw Davies3cd0fde2010-02-02 13:36:25 +00001427 *clsid = This->unmarshal_class;
1428 return S_OK;
Huw Davies39710f82010-02-02 11:52:51 +00001429}
1430
1431static 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);
Huw Davies3cd0fde2010-02-02 13:36:25 +00001436 TRACE("(%p)->(%s, %p, %08x, %p, %08x, %p)\n", This, debugstr_guid(iid), obj, dwDestContext,
Huw Davies39710f82010-02-02 11:52:51 +00001437 pvDestContext, mshlflags, size);
1438
Huw Davies3cd0fde2010-02-02 13:36:25 +00001439 return CoGetMarshalSizeMax(size, &IID_IWineRowServer, This->outer, dwDestContext, pvDestContext,
1440 mshlflags);
Huw Davies39710f82010-02-02 11:52:51 +00001441}
1442
1443static 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);
Huw Davies3cd0fde2010-02-02 13:36:25 +00001448 TRACE("(%p)->(%p, %s, %p, %08x, %p, %08x)\n", This, stream, debugstr_guid(iid), obj, dwDestContext,
Huw Davies39710f82010-02-02 11:52:51 +00001449 pvDestContext, mshlflags);
1450
Huw Davies3cd0fde2010-02-02 13:36:25 +00001451 return CoMarshalInterface(stream, &IID_IWineRowServer, This->outer, dwDestContext, pvDestContext, mshlflags);
Huw Davies39710f82010-02-02 11:52:51 +00001452}
1453
1454static HRESULT WINAPI marshal_UnmarshalInterface(IMarshal *iface, IStream *stream,
1455 REFIID iid, void **obj)
1456{
1457 marshal *This = impl_from_IMarshal(iface);
Huw Davies3cd0fde2010-02-02 13:36:25 +00001458 HRESULT hr;
1459 IWineRowServer *server;
1460 IUnknown *proxy;
1461
1462 TRACE("(%p)->(%p, %s, %p)\n", This, stream, debugstr_guid(iid), obj);
Huw Davies39710f82010-02-02 11:52:51 +00001463 *obj = NULL;
1464
Huw Davies3cd0fde2010-02-02 13:36:25 +00001465 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
Francois Gouget3428b942010-03-20 15:24:53 +01001477 TRACE("returning %p\n", *obj);
Huw Davies3cd0fde2010-02-02 13:36:25 +00001478 return hr;
Huw Davies39710f82010-02-02 11:52:51 +00001479}
1480
1481static HRESULT WINAPI marshal_ReleaseMarshalData(IMarshal *iface, IStream *stream)
1482{
1483 marshal *This = impl_from_IMarshal(iface);
Huw Davies3cd0fde2010-02-02 13:36:25 +00001484 TRACE("(%p)->(%p)\n", This, stream);
1485 return CoReleaseMarshalData(stream);
Huw Davies39710f82010-02-02 11:52:51 +00001486}
1487
1488static 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
1496static 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
1509static 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;
Francois Gouget3428b942010-03-20 15:24:53 +01001525 TRACE("returning %p\n", *obj);
Huw Davies39710f82010-02-02 11:52:51 +00001526 return S_OK;
1527}
1528
Huw Daviesde6f3812010-01-21 11:53:25 +00001529HRESULT create_row_marshal(IUnknown *outer, void **obj)
1530{
Huw Davies39710f82010-02-02 11:52:51 +00001531 TRACE("(%p, %p)\n", outer, obj);
1532 return create_marshal(outer, &CLSID_wine_row_proxy, obj);
Huw Daviesde6f3812010-01-21 11:53:25 +00001533}
1534
1535HRESULT create_rowset_marshal(IUnknown *outer, void **obj)
1536{
Huw Davies39710f82010-02-02 11:52:51 +00001537 TRACE("(%p, %p)\n", outer, obj);
1538 return create_marshal(outer, &CLSID_wine_rowset_proxy, obj);
Huw Daviesde6f3812010-01-21 11:53:25 +00001539}