| /* | |
| * Row and rowset servers / proxies. | |
| * | |
| * Copyright 2010 Huw Davies | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| */ | |
| #include <stdarg.h> | |
| #include <string.h> | |
| #define COBJMACROS | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "wingdi.h" | |
| #include "winuser.h" | |
| #include "winerror.h" | |
| #include "objbase.h" | |
| #include "oleauto.h" | |
| #include "oledb.h" | |
| #include "row_server.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(oledb); | |
| static inline DBLENGTH db_type_size(DBTYPE type, DBLENGTH var_len) | |
| { | |
| switch(type) | |
| { | |
| case DBTYPE_I1: | |
| case DBTYPE_UI1: | |
| return 1; | |
| case DBTYPE_I2: | |
| case DBTYPE_UI2: | |
| return 2; | |
| case DBTYPE_I4: | |
| case DBTYPE_UI4: | |
| case DBTYPE_R4: | |
| return 4; | |
| case DBTYPE_I8: | |
| case DBTYPE_UI8: | |
| case DBTYPE_R8: | |
| return 8; | |
| case DBTYPE_CY: | |
| return sizeof(CY); | |
| case DBTYPE_FILETIME: | |
| return sizeof(FILETIME); | |
| case DBTYPE_BSTR: | |
| return sizeof(BSTR); | |
| case DBTYPE_GUID: | |
| return sizeof(GUID); | |
| case DBTYPE_WSTR: | |
| return var_len; | |
| default: | |
| FIXME("Unhandled type %04x\n", type); | |
| return 0; | |
| } | |
| } | |
| typedef struct | |
| { | |
| IWineRowServer IWineRowServer_iface; | |
| LONG ref; | |
| CLSID class; | |
| IMarshal *marshal; | |
| IUnknown *inner_unk; | |
| } server; | |
| static inline server *impl_from_IWineRowServer(IWineRowServer *iface) | |
| { | |
| return CONTAINING_RECORD(iface, server, IWineRowServer_iface); | |
| } | |
| static HRESULT WINAPI server_QueryInterface(IWineRowServer *iface, REFIID riid, void **obj) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj); | |
| *obj = NULL; | |
| if(IsEqualIID(riid, &IID_IUnknown) || | |
| IsEqualIID(riid, &IID_IWineRowServer)) | |
| { | |
| *obj = iface; | |
| } | |
| else | |
| { | |
| if(!IsEqualIID(riid, &IID_IMarshal)) /* We use standard marshalling */ | |
| FIXME("interface %s not implemented\n", debugstr_guid(riid)); | |
| return E_NOINTERFACE; | |
| } | |
| IWineRowServer_AddRef(iface); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI server_AddRef(IWineRowServer *iface) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| TRACE("(%p)\n", This); | |
| return InterlockedIncrement(&This->ref); | |
| } | |
| static ULONG WINAPI server_Release(IWineRowServer *iface) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| LONG ref; | |
| TRACE("(%p)\n", This); | |
| ref = InterlockedDecrement(&This->ref); | |
| if(ref == 0) | |
| { | |
| IMarshal_Release(This->marshal); | |
| if(This->inner_unk) IUnknown_Release(This->inner_unk); | |
| HeapFree(GetProcessHeap(), 0, This); | |
| } | |
| return ref; | |
| } | |
| static HRESULT WINAPI server_SetInnerUnk(IWineRowServer *iface, IUnknown *inner) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| if(This->inner_unk) IUnknown_Release(This->inner_unk); | |
| if(inner) IUnknown_AddRef(inner); | |
| This->inner_unk = inner; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI server_GetMarshal(IWineRowServer *iface, IMarshal **marshal) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| IMarshal_AddRef(This->marshal); | |
| *marshal = This->marshal; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI server_GetColumns(IWineRowServer* iface, DBORDINAL num_cols, | |
| wine_getcolumns_in *in_data, wine_getcolumns_out *out_data) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| HRESULT hr; | |
| DBORDINAL i; | |
| DBCOLUMNACCESS *cols; | |
| IRow *row; | |
| TRACE("(%p)->(%ld, %p, %p)\n", This, num_cols, in_data, out_data); | |
| hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRow, (void**)&row); | |
| if(FAILED(hr)) return hr; | |
| cols = CoTaskMemAlloc(num_cols * sizeof(cols[0])); | |
| for(i = 0; i < num_cols; i++) | |
| { | |
| TRACE("%ld:\tmax_len %ld type %04x\n", i, in_data[i].max_len, in_data[i].type); | |
| cols[i].pData = CoTaskMemAlloc(db_type_size(in_data[i].type, in_data[i].max_len)); | |
| cols[i].columnid = in_data[i].columnid; | |
| cols[i].cbMaxLen = in_data[i].max_len; | |
| cols[i].wType = in_data[i].type; | |
| cols[i].bPrecision = in_data[i].precision; | |
| cols[i].bScale = in_data[i].scale; | |
| } | |
| hr = IRow_GetColumns(row, num_cols, cols); | |
| IRow_Release(row); | |
| for(i = 0; i < num_cols; i++) | |
| { | |
| VariantInit(&out_data[i].v); | |
| if(cols[i].dwStatus == DBSTATUS_S_OK) | |
| { | |
| V_VT(&out_data[i].v) = in_data[i].type; | |
| memcpy(&V_I1(&out_data[i].v), cols[i].pData, cols[i].cbDataLen); | |
| } | |
| CoTaskMemFree(cols[i].pData); | |
| out_data[i].data_len = cols[i].cbDataLen; | |
| out_data[i].status = cols[i].dwStatus; | |
| } | |
| CoTaskMemFree(cols); | |
| return hr; | |
| } | |
| static HRESULT WINAPI server_GetSourceRowset(IWineRowServer* iface, REFIID riid, IUnknown **ppRowset, | |
| HROW *phRow) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| FIXME("(%p): stub\n", This); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI server_Open(IWineRowServer* iface, IUnknown *pUnkOuter, DBID *pColumnID, | |
| REFGUID rguidColumnType, DWORD dwBindFlags, REFIID riid, | |
| IUnknown **ppUnk) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| IRow *row; | |
| HRESULT hr; | |
| IWineRowServer *new_server; | |
| IMarshal *marshal; | |
| IUnknown *obj; | |
| TRACE("(%p)->(%p, %p, %s, %08x, %s, %p)\n", This, pUnkOuter, pColumnID, debugstr_guid(rguidColumnType), | |
| dwBindFlags, debugstr_guid(riid), ppUnk); | |
| *ppUnk = NULL; | |
| hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRow, (void**)&row); | |
| if(FAILED(hr)) return hr; | |
| if(IsEqualGUID(rguidColumnType, &DBGUID_ROWSET)) | |
| hr = CoCreateInstance(&CLSID_wine_rowset_server, NULL, CLSCTX_INPROC_SERVER, &IID_IWineRowServer, (void**)&new_server); | |
| else | |
| { | |
| FIXME("Unhandled object %s\n", debugstr_guid(rguidColumnType)); | |
| hr = E_NOTIMPL; | |
| } | |
| if(FAILED(hr)) | |
| { | |
| IRow_Release(row); | |
| return hr; | |
| } | |
| IWineRowServer_GetMarshal(new_server, &marshal); | |
| hr = IRow_Open(row, (IUnknown*)marshal, pColumnID, rguidColumnType, dwBindFlags, &IID_IUnknown, &obj); | |
| IMarshal_Release(marshal); | |
| IRow_Release(row); | |
| if(FAILED(hr)) | |
| { | |
| IWineRowServer_Release(new_server); | |
| return hr; | |
| } | |
| IWineRowServer_SetInnerUnk(new_server, obj); | |
| hr = IUnknown_QueryInterface(obj, riid, (void**)ppUnk); | |
| IUnknown_Release(obj); | |
| TRACE("returning %08x\n", hr); | |
| return hr; | |
| } | |
| static HRESULT WINAPI server_SetColumns(IWineRowServer* iface, DBORDINAL num_cols, | |
| wine_setcolumns_in *in_data, DBSTATUS *status) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| HRESULT hr; | |
| DBORDINAL i; | |
| DBCOLUMNACCESS *cols; | |
| IRowChange *row_change; | |
| TRACE("(%p)->(%ld, %p, %p)\n", This, num_cols, in_data, status); | |
| hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowChange, (void**)&row_change); | |
| if(FAILED(hr)) return hr; | |
| cols = CoTaskMemAlloc(num_cols * sizeof(cols[0])); | |
| for(i = 0; i < num_cols; i++) | |
| { | |
| TRACE("%ld:\ttype %04x\n", i, in_data[i].type); | |
| cols[i].pData = CoTaskMemAlloc(db_type_size(in_data[i].type, in_data[i].max_len)); | |
| memcpy(cols[i].pData, &V_I1(&in_data[i].v), db_type_size(in_data[i].type, in_data[i].max_len)); | |
| cols[i].columnid = in_data[i].columnid; | |
| cols[i].cbDataLen = in_data[i].data_len; | |
| cols[i].dwStatus = in_data[i].status; | |
| cols[i].cbMaxLen = in_data[i].max_len; | |
| cols[i].wType = in_data[i].type; | |
| cols[i].bPrecision = in_data[i].precision; | |
| cols[i].bScale = in_data[i].scale; | |
| } | |
| hr = IRowChange_SetColumns(row_change, num_cols, cols); | |
| IRowChange_Release(row_change); | |
| for(i = 0; i < num_cols; i++) | |
| { | |
| CoTaskMemFree(cols[i].pData); | |
| status[i] = cols[i].dwStatus; | |
| } | |
| CoTaskMemFree(cols); | |
| return hr; | |
| } | |
| static HRESULT WINAPI server_AddRefRows(IWineRowServer* iface, DBCOUNTITEM cRows, | |
| const HROW rghRows[], DBREFCOUNT rgRefCounts[], | |
| DBROWSTATUS rgRowStatus[]) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| IRowset *rowset; | |
| HRESULT hr; | |
| TRACE("(%p)->(%ld, %p, %p, %p)\n", This, cRows, rghRows, rgRefCounts, rgRowStatus); | |
| hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowset, (void**)&rowset); | |
| if(FAILED(hr)) return hr; | |
| hr = IRowset_AddRefRows(rowset, cRows, rghRows, rgRefCounts, rgRowStatus); | |
| IRowset_Release(rowset); | |
| TRACE("returning %08x\n", hr); | |
| return hr; | |
| } | |
| static HRESULT WINAPI server_GetData(IWineRowServer* iface, HROW hRow, | |
| HACCESSOR hAccessor, BYTE *pData, DWORD size) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| IRowset *rowset; | |
| HRESULT hr; | |
| TRACE("(%p)->(%08lx, %08lx, %p, %d)\n", This, hRow, hAccessor, pData, size); | |
| hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowset, (void**)&rowset); | |
| if(FAILED(hr)) return hr; | |
| hr = IRowset_GetData(rowset, hRow, hAccessor, pData); | |
| IRowset_Release(rowset); | |
| TRACE("returning %08x\n", hr); | |
| return hr; | |
| } | |
| static HRESULT WINAPI server_GetNextRows(IWineRowServer* iface, HCHAPTER hReserved, DBROWOFFSET lRowsOffset, | |
| DBROWCOUNT cRows, DBCOUNTITEM *pcRowObtained, HROW **prghRows) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| IRowset *rowset; | |
| HRESULT hr; | |
| TRACE("(%p)->(%08lx, %ld, %ld, %p, %p)\n", This, hReserved, lRowsOffset, cRows, pcRowObtained, prghRows); | |
| hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowset, (void**)&rowset); | |
| if(FAILED(hr)) return hr; | |
| *prghRows = NULL; | |
| hr = IRowset_GetNextRows(rowset, hReserved, lRowsOffset, cRows, pcRowObtained, prghRows); | |
| IRowset_Release(rowset); | |
| TRACE("returning %08x, got %ld rows\n", hr, *pcRowObtained); | |
| return hr; | |
| } | |
| static HRESULT WINAPI server_ReleaseRows(IWineRowServer* iface, DBCOUNTITEM cRows, const HROW rghRows[], | |
| DBROWOPTIONS rgRowOptions[], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[]) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| IRowset *rowset; | |
| HRESULT hr; | |
| TRACE("(%p)->(%ld, %p, %p, %p, %p)\n", This, cRows, rghRows, rgRowOptions, rgRefCounts, rgRowStatus); | |
| hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowset, (void**)&rowset); | |
| if(FAILED(hr)) return hr; | |
| hr = IRowset_ReleaseRows(rowset, cRows, rghRows, rgRowOptions, rgRefCounts, rgRowStatus); | |
| IRowset_Release(rowset); | |
| TRACE("returning %08x\n", hr); | |
| return hr; | |
| } | |
| static HRESULT WINAPI server_RestartPosition(IWineRowServer* iface, HCHAPTER hReserved) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| FIXME("(%p)->(%08lx): stub\n", This, hReserved); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI server_Compare(IWineRowServer *iface, HCHAPTER hReserved, DBBKMARK cbBookmark1, | |
| const BYTE *pBookmark1, DBBKMARK cbBookmark2, const BYTE *pBookmark2, | |
| DBCOMPARE *pComparison) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| FIXME("(%p): stub\n", This); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI server_GetRowsAt(IWineRowServer *iface, HWATCHREGION hReserved1, HCHAPTER hReserved2, | |
| DBBKMARK cbBookmark, const BYTE *pBookmark, DBROWOFFSET lRowsOffset, | |
| DBROWCOUNT cRows, DBCOUNTITEM *pcRowsObtained, HROW **prghRows) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| IRowsetLocate *rowsetlocate; | |
| HRESULT hr; | |
| TRACE("(%p)->(%08lx, %08lx, %ld, %p, %ld, %ld, %p, %p\n", This, hReserved1, hReserved2, cbBookmark, pBookmark, lRowsOffset, cRows, | |
| pcRowsObtained, prghRows); | |
| *prghRows = NULL; | |
| hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowsetLocate, (void**)&rowsetlocate); | |
| if(FAILED(hr)) return hr; | |
| hr = IRowsetLocate_GetRowsAt(rowsetlocate, hReserved1, hReserved2, cbBookmark, pBookmark, lRowsOffset, | |
| cRows, pcRowsObtained, prghRows); | |
| IRowsetLocate_Release(rowsetlocate); | |
| TRACE("returning %08x\n", hr); | |
| return hr; | |
| } | |
| static HRESULT WINAPI server_GetRowsByBookmark(IWineRowServer *iface, HCHAPTER hReserved, DBCOUNTITEM cRows, | |
| const DBBKMARK rgcbBookmarks[], const BYTE * rgpBookmarks[], | |
| HROW rghRows[], DBROWSTATUS rgRowStatus[]) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| FIXME("(%p): stub\n", This); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI server_Hash(IWineRowServer *iface, HCHAPTER hReserved, DBBKMARK cBookmarks, | |
| const DBBKMARK rgcbBookmarks[], const BYTE * rgpBookmarks[], | |
| DBHASHVALUE rgHashedValues[], DBROWSTATUS rgBookmarkStatus[]) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| FIXME("(%p): stub\n", This); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI server_GetProperties(IWineRowServer* iface, ULONG cPropertyIDSets, | |
| const DBPROPIDSET *rgPropertyIDSets, ULONG *pcPropertySets, | |
| DBPROPSET **prgPropertySets) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| IRowsetInfo *rowsetinfo; | |
| HRESULT hr; | |
| TRACE("(%p)->(%d, %p, %p, %p)\n", This, cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets); | |
| hr = IUnknown_QueryInterface(This->inner_unk, &IID_IRowsetInfo, (void**)&rowsetinfo); | |
| if(FAILED(hr)) return hr; | |
| hr = IRowsetInfo_GetProperties(rowsetinfo, cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets); | |
| IRowsetInfo_Release(rowsetinfo); | |
| TRACE("returning %08x\n", hr); | |
| return hr; | |
| } | |
| static HRESULT WINAPI server_GetReferencedRowset(IWineRowServer* iface, DBORDINAL iOrdinal, | |
| REFIID riid, IUnknown **ppReferencedRowset) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| FIXME("(%p): stub\n", This); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI server_GetSpecification(IWineRowServer* iface, REFIID riid, | |
| IUnknown **ppSpecification) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| FIXME("(%p): stub\n", This); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI server_AddRefAccessor(IWineRowServer* iface, HACCESSOR hAccessor, | |
| DBREFCOUNT *pcRefCount) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| FIXME("(%p): stub\n", This); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI server_CreateAccessor(IWineRowServer* iface, DBACCESSORFLAGS dwAccessorFlags, | |
| DBCOUNTITEM cBindings, const DBBINDING *rgBindings, DBLENGTH cbRowSize, | |
| HACCESSOR *phAccessor, DBBINDSTATUS *rgStatus) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| HRESULT hr; | |
| IAccessor *accessor; | |
| TRACE("(%p)->(%08x, %ld, %p, %ld, %p, %p)\n", This, dwAccessorFlags, cBindings, rgBindings, cbRowSize, phAccessor, rgStatus); | |
| hr = IUnknown_QueryInterface(This->inner_unk, &IID_IAccessor, (void**)&accessor); | |
| if(FAILED(hr)) return hr; | |
| hr = IAccessor_CreateAccessor(accessor, dwAccessorFlags, cBindings, rgBindings, cbRowSize, phAccessor, rgStatus); | |
| IAccessor_Release(accessor); | |
| TRACE("returning %08x, accessor %08lx\n", hr, *phAccessor); | |
| return hr; | |
| } | |
| static HRESULT WINAPI server_GetBindings(IWineRowServer* iface, HACCESSOR hAccessor, | |
| DBACCESSORFLAGS *pdwAccessorFlags, DBCOUNTITEM *pcBindings, | |
| DBBINDING **prgBindings) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| HRESULT hr; | |
| IAccessor *accessor; | |
| TRACE("(%p)->(%08lx, %p, %p, %p)\n", This, hAccessor, pdwAccessorFlags, pcBindings, prgBindings); | |
| hr = IUnknown_QueryInterface(This->inner_unk, &IID_IAccessor, (void**)&accessor); | |
| if(FAILED(hr)) return hr; | |
| hr = IAccessor_GetBindings(accessor, hAccessor, pdwAccessorFlags, pcBindings, prgBindings); | |
| IAccessor_Release(accessor); | |
| TRACE("returning %08x\n", hr); | |
| return hr; | |
| } | |
| static HRESULT WINAPI server_ReleaseAccessor(IWineRowServer* iface, HACCESSOR hAccessor, | |
| DBREFCOUNT *pcRefCount) | |
| { | |
| server *This = impl_from_IWineRowServer(iface); | |
| HRESULT hr; | |
| IAccessor *accessor; | |
| TRACE("(%p)->(%08lx, %p)\n", This, hAccessor, pcRefCount); | |
| hr = IUnknown_QueryInterface(This->inner_unk, &IID_IAccessor, (void**)&accessor); | |
| if(FAILED(hr)) return hr; | |
| hr = IAccessor_ReleaseAccessor(accessor, hAccessor, pcRefCount); | |
| IAccessor_Release(accessor); | |
| return hr; | |
| } | |
| static const IWineRowServerVtbl server_vtbl = | |
| { | |
| server_QueryInterface, | |
| server_AddRef, | |
| server_Release, | |
| server_SetInnerUnk, | |
| server_GetMarshal, | |
| server_GetColumns, | |
| server_GetSourceRowset, | |
| server_Open, | |
| server_SetColumns, | |
| server_AddRefRows, | |
| server_GetData, | |
| server_GetNextRows, | |
| server_ReleaseRows, | |
| server_RestartPosition, | |
| server_Compare, | |
| server_GetRowsAt, | |
| server_GetRowsByBookmark, | |
| server_Hash, | |
| server_GetProperties, | |
| server_GetReferencedRowset, | |
| server_GetSpecification, | |
| server_AddRefAccessor, | |
| server_CreateAccessor, | |
| server_GetBindings, | |
| server_ReleaseAccessor | |
| }; | |
| static HRESULT create_server(IUnknown *outer, const CLSID *class, void **obj) | |
| { | |
| server *server; | |
| TRACE("(%p, %s, %p)\n", outer, debugstr_guid(class), obj); | |
| *obj = NULL; | |
| server = HeapAlloc(GetProcessHeap(), 0, sizeof(*server)); | |
| if(!server) return E_OUTOFMEMORY; | |
| server->IWineRowServer_iface.lpVtbl = &server_vtbl; | |
| server->ref = 1; | |
| server->class = *class; | |
| server->inner_unk = NULL; | |
| if(IsEqualGUID(class, &CLSID_wine_row_server)) | |
| create_row_marshal((IUnknown*)server, (void**)&server->marshal); | |
| else if(IsEqualGUID(class, &CLSID_wine_rowset_server)) | |
| create_rowset_marshal((IUnknown*)server, (void**)&server->marshal); | |
| else | |
| ERR("create_server called with class %s\n", debugstr_guid(class)); | |
| *obj = server; | |
| return S_OK; | |
| } | |
| HRESULT create_row_server(IUnknown *outer, void **obj) | |
| { | |
| return create_server(outer, &CLSID_wine_row_server, obj); | |
| } | |
| HRESULT create_rowset_server(IUnknown *outer, void **obj) | |
| { | |
| return create_server(outer, &CLSID_wine_rowset_server, obj); | |
| } | |
| typedef struct | |
| { | |
| IRow IRow_iface; | |
| IRowChange IRowChange_iface; | |
| LONG ref; | |
| IWineRowServer *server; | |
| } row_proxy; | |
| static inline row_proxy *impl_from_IRow(IRow *iface) | |
| { | |
| return CONTAINING_RECORD(iface, row_proxy, IRow_iface); | |
| } | |
| static inline row_proxy *impl_from_IRowChange(IRowChange *iface) | |
| { | |
| return CONTAINING_RECORD(iface, row_proxy, IRowChange_iface); | |
| } | |
| static HRESULT WINAPI row_QueryInterface(IRow *iface, REFIID iid, void **obj) | |
| { | |
| row_proxy *This = impl_from_IRow(iface); | |
| TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(iid), obj); | |
| if(IsEqualIID(iid, &IID_IUnknown) || | |
| IsEqualIID(iid, &IID_IRow)) | |
| { | |
| *obj = &This->IRow_iface; | |
| } | |
| else if(IsEqualIID(iid, &IID_IRowChange)) | |
| { | |
| *obj = &This->IRowChange_iface; | |
| } | |
| else | |
| { | |
| FIXME("interface %s not implemented\n", debugstr_guid(iid)); | |
| return E_NOINTERFACE; | |
| } | |
| IRow_AddRef(iface); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI row_AddRef(IRow *iface) | |
| { | |
| row_proxy *This = impl_from_IRow(iface); | |
| TRACE("(%p)\n", This); | |
| return InterlockedIncrement(&This->ref); | |
| } | |
| static ULONG WINAPI row_Release(IRow *iface) | |
| { | |
| row_proxy *This = impl_from_IRow(iface); | |
| LONG ref; | |
| TRACE("(%p)\n", This); | |
| ref = InterlockedDecrement(&This->ref); | |
| if(ref == 0) | |
| { | |
| if(This->server) IWineRowServer_Release(This->server); | |
| HeapFree(GetProcessHeap(), 0, This); | |
| } | |
| return ref; | |
| } | |
| static HRESULT WINAPI row_GetColumns(IRow* iface, DBORDINAL cColumns, DBCOLUMNACCESS rgColumns[]) | |
| { | |
| row_proxy *This = impl_from_IRow(iface); | |
| DBORDINAL i; | |
| wine_getcolumns_in *in_data; | |
| wine_getcolumns_out *out_data; | |
| HRESULT hr; | |
| TRACE("(%p)->(%ld, %p)\n", This, cColumns, rgColumns); | |
| in_data = CoTaskMemAlloc(cColumns * sizeof(in_data[0])); | |
| out_data = CoTaskMemAlloc(cColumns * sizeof(out_data[0])); | |
| for(i = 0; i < cColumns; i++) | |
| { | |
| TRACE("%ld:\tdata %p data_len %ld status %08x max_len %ld type %04x\n", i, rgColumns[i].pData, | |
| rgColumns[i].cbDataLen, rgColumns[i].dwStatus, rgColumns[i].cbMaxLen, rgColumns[i].wType); | |
| in_data[i].columnid = rgColumns[i].columnid; | |
| in_data[i].max_len = rgColumns[i].cbMaxLen; | |
| in_data[i].type = rgColumns[i].wType; | |
| in_data[i].precision = rgColumns[i].bPrecision; | |
| in_data[i].scale = rgColumns[i].bScale; | |
| } | |
| hr = IWineRowServer_GetColumns(This->server, cColumns, in_data, out_data); | |
| for(i = 0; i < cColumns; i++) | |
| { | |
| rgColumns[i].cbDataLen = out_data[i].data_len; | |
| rgColumns[i].dwStatus = out_data[i].status; | |
| if(rgColumns[i].dwStatus == DBSTATUS_S_OK) | |
| memcpy(rgColumns[i].pData, &V_I1(&out_data[i].v), out_data[i].data_len); | |
| } | |
| CoTaskMemFree(out_data); | |
| CoTaskMemFree(in_data); | |
| return hr; | |
| } | |
| static HRESULT WINAPI row_GetSourceRowset(IRow* iface, REFIID riid, IUnknown **ppRowset, | |
| HROW *phRow) | |
| { | |
| row_proxy *This = impl_from_IRow(iface); | |
| FIXME("(%p)->(%s, %p, %p): stub\n", This, debugstr_guid(riid), ppRowset, phRow); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI row_Open(IRow* iface, IUnknown *pUnkOuter, | |
| DBID *pColumnID, REFGUID rguidColumnType, | |
| DWORD dwBindFlags, REFIID riid, IUnknown **ppUnk) | |
| { | |
| row_proxy *This = impl_from_IRow(iface); | |
| TRACE("(%p)->(%p, %p, %s, %08x, %s, %p)\n", This, pUnkOuter, pColumnID, debugstr_guid(rguidColumnType), | |
| dwBindFlags, debugstr_guid(riid), ppUnk); | |
| if(pUnkOuter) | |
| { | |
| FIXME("Aggregation not supported\n"); | |
| return CLASS_E_NOAGGREGATION; | |
| } | |
| return IWineRowServer_Open(This->server, pUnkOuter, pColumnID, rguidColumnType, dwBindFlags, riid, ppUnk); | |
| } | |
| static const IRowVtbl row_vtbl = | |
| { | |
| row_QueryInterface, | |
| row_AddRef, | |
| row_Release, | |
| row_GetColumns, | |
| row_GetSourceRowset, | |
| row_Open | |
| }; | |
| static HRESULT WINAPI row_change_QueryInterface(IRowChange *iface, REFIID iid, void **obj) | |
| { | |
| row_proxy *This = impl_from_IRowChange(iface); | |
| return IRow_QueryInterface(&This->IRow_iface, iid, obj); | |
| } | |
| static ULONG WINAPI row_change_AddRef(IRowChange *iface) | |
| { | |
| row_proxy *This = impl_from_IRowChange(iface); | |
| return IRow_AddRef(&This->IRow_iface); | |
| } | |
| static ULONG WINAPI row_change_Release(IRowChange *iface) | |
| { | |
| row_proxy *This = impl_from_IRowChange(iface); | |
| return IRow_Release(&This->IRow_iface); | |
| } | |
| static HRESULT WINAPI row_change_SetColumns(IRowChange *iface, DBORDINAL cColumns, | |
| DBCOLUMNACCESS rgColumns[]) | |
| { | |
| row_proxy *This = impl_from_IRowChange(iface); | |
| HRESULT hr; | |
| wine_setcolumns_in *in_data; | |
| DBSTATUS *status; | |
| DBORDINAL i; | |
| TRACE("(%p)->(%ld, %p)\n", This, cColumns, rgColumns); | |
| in_data = CoTaskMemAlloc(cColumns * sizeof(in_data[0])); | |
| status = CoTaskMemAlloc(cColumns * sizeof(status[0])); | |
| for(i = 0; i < cColumns; i++) | |
| { | |
| TRACE("%ld: wtype %04x max %08lx len %08lx\n", i, rgColumns[i].wType, rgColumns[i].cbMaxLen, rgColumns[i].cbDataLen); | |
| V_VT(&in_data[i].v) = rgColumns[i].wType; | |
| memcpy(&V_I1(&in_data[i].v), rgColumns[i].pData, db_type_size(rgColumns[i].wType, rgColumns[i].cbDataLen)); | |
| in_data[i].columnid = rgColumns[i].columnid; | |
| in_data[i].data_len = rgColumns[i].cbDataLen; | |
| in_data[i].status = rgColumns[i].dwStatus; | |
| in_data[i].max_len = rgColumns[i].cbMaxLen; | |
| in_data[i].type = rgColumns[i].wType; | |
| in_data[i].precision = rgColumns[i].bPrecision; | |
| in_data[i].scale = rgColumns[i].bScale; | |
| } | |
| hr = IWineRowServer_SetColumns(This->server, cColumns, in_data, status); | |
| for(i = 0; i < cColumns; i++) | |
| rgColumns[i].dwStatus = status[i]; | |
| CoTaskMemFree(status); | |
| CoTaskMemFree(in_data); | |
| return hr; | |
| } | |
| static const IRowChangeVtbl row_change_vtbl = | |
| { | |
| row_change_QueryInterface, | |
| row_change_AddRef, | |
| row_change_Release, | |
| row_change_SetColumns | |
| }; | |
| static HRESULT create_row_proxy(IWineRowServer *server, IUnknown **obj) | |
| { | |
| row_proxy *proxy; | |
| TRACE("(%p, %p)\n", server, obj); | |
| *obj = NULL; | |
| proxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*proxy)); | |
| if(!proxy) return E_OUTOFMEMORY; | |
| proxy->IRow_iface.lpVtbl = &row_vtbl; | |
| proxy->IRowChange_iface.lpVtbl = &row_change_vtbl; | |
| proxy->ref = 1; | |
| IWineRowServer_AddRef(server); | |
| proxy->server = server; | |
| *obj = (IUnknown*)&proxy->IRow_iface; | |
| TRACE("returning %p\n", *obj); | |
| return S_OK; | |
| } | |
| typedef struct | |
| { | |
| IRowsetLocate IRowsetLocate_iface; | |
| IRowsetInfo IRowsetInfo_iface; | |
| IAccessor IAccessor_iface; | |
| LONG ref; | |
| IWineRowServer *server; | |
| } rowset_proxy; | |
| static inline rowset_proxy *impl_from_IRowsetLocate(IRowsetLocate *iface) | |
| { | |
| return CONTAINING_RECORD(iface, rowset_proxy, IRowsetLocate_iface); | |
| } | |
| static inline rowset_proxy *impl_from_IRowsetInfo(IRowsetInfo *iface) | |
| { | |
| return CONTAINING_RECORD(iface, rowset_proxy, IRowsetInfo_iface); | |
| } | |
| static inline rowset_proxy *impl_from_IAccessor(IAccessor *iface) | |
| { | |
| return CONTAINING_RECORD(iface, rowset_proxy, IAccessor_iface); | |
| } | |
| static HRESULT WINAPI rowsetlocate_QueryInterface(IRowsetLocate *iface, REFIID iid, void **obj) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetLocate(iface); | |
| TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(iid), obj); | |
| *obj = NULL; | |
| if(IsEqualIID(iid, &IID_IUnknown) || | |
| IsEqualIID(iid, &IID_IRowset) || | |
| IsEqualIID(iid, &IID_IRowsetLocate)) | |
| { | |
| *obj = &This->IRowsetLocate_iface; | |
| } | |
| else if(IsEqualIID(iid, &IID_IRowsetInfo)) | |
| { | |
| *obj = &This->IRowsetInfo_iface; | |
| } | |
| else if(IsEqualIID(iid, &IID_IAccessor)) | |
| { | |
| *obj = &This->IAccessor_iface; | |
| } | |
| else | |
| { | |
| FIXME("interface %s not implemented\n", debugstr_guid(iid)); | |
| return E_NOINTERFACE; | |
| } | |
| IRowsetLocate_AddRef(iface); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI rowsetlocate_AddRef(IRowsetLocate *iface) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetLocate(iface); | |
| TRACE("(%p)\n", This); | |
| return InterlockedIncrement(&This->ref); | |
| } | |
| static ULONG WINAPI rowsetlocate_Release(IRowsetLocate *iface) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetLocate(iface); | |
| LONG ref; | |
| TRACE("(%p)\n", This); | |
| ref = InterlockedDecrement(&This->ref); | |
| if(ref == 0) | |
| { | |
| if(This->server) IWineRowServer_Release(This->server); | |
| HeapFree(GetProcessHeap(), 0, This); | |
| } | |
| return ref; | |
| } | |
| static HRESULT WINAPI rowsetlocate_AddRefRows(IRowsetLocate *iface, DBCOUNTITEM cRows, const HROW rghRows[], | |
| DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[]) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetLocate(iface); | |
| HRESULT hr; | |
| DBREFCOUNT *refs = rgRefCounts; | |
| DBSTATUS *stats = rgRowStatus; | |
| TRACE("(%p)->(%ld, %p, %p, %p)\n", This, cRows, rghRows, rgRefCounts, rgRowStatus); | |
| if(!refs) refs = CoTaskMemAlloc(cRows * sizeof(refs[0])); | |
| if(!stats) stats = CoTaskMemAlloc(cRows * sizeof(stats[0])); | |
| hr = IWineRowServer_AddRefRows(This->server, cRows, rghRows, refs, stats); | |
| if(refs != rgRefCounts) CoTaskMemFree(refs); | |
| if(stats != rgRowStatus) CoTaskMemFree(stats); | |
| return hr; | |
| } | |
| static HRESULT WINAPI rowsetlocate_GetData(IRowsetLocate *iface, HROW hRow, HACCESSOR hAccessor, void *pData) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetLocate(iface); | |
| HRESULT hr; | |
| IAccessor *accessor; | |
| DBACCESSORFLAGS flags; | |
| DBCOUNTITEM count, i; | |
| DBBINDING *bindings; | |
| DWORD max_len = 0; | |
| TRACE("(%p)->(%lx, %lx, %p)\n", This, hRow, hAccessor, pData); | |
| hr = IRowsetLocate_QueryInterface(iface, &IID_IAccessor, (void**)&accessor); | |
| if(FAILED(hr)) return hr; | |
| hr = IAccessor_GetBindings(accessor, hAccessor, &flags, &count, &bindings); | |
| IAccessor_Release(accessor); | |
| if(FAILED(hr)) return hr; | |
| TRACE("got %ld bindings\n", count); | |
| for(i = 0; i < count; i++) | |
| { | |
| TRACE("%ld\tord %ld offs: val %ld len %ld stat %ld, part %x, max len %ld type %04x\n", | |
| i, bindings[i].iOrdinal, bindings[i].obValue, bindings[i].obLength, bindings[i].obStatus, | |
| bindings[i].dwPart, bindings[i].cbMaxLen, bindings[i].wType); | |
| if(bindings[i].dwPart & DBPART_LENGTH && bindings[i].obLength >= max_len) | |
| max_len = bindings[i].obLength + sizeof(DBLENGTH); | |
| if(bindings[i].dwPart & DBPART_STATUS && bindings[i].obStatus >= max_len) | |
| max_len = bindings[i].obStatus + sizeof(DWORD); | |
| if(bindings[i].dwPart & DBPART_VALUE && bindings[i].obValue >= max_len) | |
| max_len = bindings[i].obValue + db_type_size(bindings[i].wType, bindings[i].cbMaxLen); | |
| } | |
| TRACE("max_len %d\n", max_len); | |
| CoTaskMemFree(bindings); | |
| hr = IWineRowServer_GetData(This->server, hRow, hAccessor, pData, max_len); | |
| return hr; | |
| } | |
| static HRESULT WINAPI rowsetlocate_GetNextRows(IRowsetLocate *iface, HCHAPTER hReserved, DBROWOFFSET lRowsOffset, | |
| DBROWCOUNT cRows, DBCOUNTITEM *pcRowObtained, HROW **prghRows) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetLocate(iface); | |
| HRESULT hr; | |
| HROW *rows = NULL; | |
| TRACE("(%p)->(%08lx, %ld, %ld, %p, %p)\n", This, hReserved, lRowsOffset, cRows, pcRowObtained, prghRows); | |
| hr = IWineRowServer_GetNextRows(This->server, hReserved, lRowsOffset, cRows, pcRowObtained, &rows); | |
| if(*prghRows) | |
| { | |
| memcpy(*prghRows, rows, *pcRowObtained * sizeof(rows[0])); | |
| CoTaskMemFree(rows); | |
| } | |
| else | |
| *prghRows = rows; | |
| return hr; | |
| } | |
| static HRESULT WINAPI rowsetlocate_ReleaseRows(IRowsetLocate *iface, DBCOUNTITEM cRows, const HROW rghRows[], | |
| DBROWOPTIONS rgRowOptions[], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[]) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetLocate(iface); | |
| HRESULT hr; | |
| DBROWOPTIONS *options = rgRowOptions; | |
| DBREFCOUNT *refs = rgRefCounts; | |
| DBROWSTATUS *status = rgRowStatus; | |
| TRACE("(%p)->(%ld, %p, %p, %p, %p)\n", This, cRows, rghRows, rgRowOptions, rgRefCounts, rgRowStatus); | |
| if(!options) | |
| { | |
| options = CoTaskMemAlloc(cRows * sizeof(options[0])); | |
| memset(options, 0, cRows * sizeof(options[0])); | |
| } | |
| if(!refs) refs = CoTaskMemAlloc(cRows * sizeof(refs[0])); | |
| if(!status) status = CoTaskMemAlloc(cRows * sizeof(status[0])); | |
| hr = IWineRowServer_ReleaseRows(This->server, cRows, rghRows, options, refs, status); | |
| if(status != rgRowStatus) CoTaskMemFree(status); | |
| if(refs != rgRefCounts) CoTaskMemFree(refs); | |
| if(options != rgRowOptions) CoTaskMemFree(options); | |
| return hr; | |
| } | |
| static HRESULT WINAPI rowsetlocate_RestartPosition(IRowsetLocate* iface, HCHAPTER hReserved) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetLocate(iface); | |
| FIXME("(%p)->(%lx): stub\n", This, hReserved); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI rowsetlocate_Compare(IRowsetLocate *iface, HCHAPTER hReserved, DBBKMARK cbBookmark1, const BYTE *pBookmark1, | |
| DBBKMARK cbBookmark2, const BYTE *pBookmark2, DBCOMPARE *pComparison) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetLocate(iface); | |
| FIXME("(%p)\n", This); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI rowsetlocate_GetRowsAt(IRowsetLocate *iface, HWATCHREGION hReserved1, HCHAPTER hReserved2, DBBKMARK cbBookmark, | |
| const BYTE *pBookmark, DBROWOFFSET lRowsOffset, DBROWCOUNT cRows, DBCOUNTITEM *pcRowsObtained, | |
| HROW **prghRows) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetLocate(iface); | |
| HRESULT hr; | |
| HROW *rows = NULL; | |
| TRACE("(%p)->(%08lx, %08lx, %ld, %p, %ld, %ld, %p, %p\n", This, hReserved1, hReserved2, cbBookmark, pBookmark, lRowsOffset, cRows, | |
| pcRowsObtained, prghRows); | |
| hr = IWineRowServer_GetRowsAt(This->server, hReserved1, hReserved2, cbBookmark, pBookmark, lRowsOffset, cRows, pcRowsObtained, &rows); | |
| if(*prghRows) | |
| { | |
| memcpy(*prghRows, rows, *pcRowsObtained * sizeof(rows[0])); | |
| CoTaskMemFree(rows); | |
| } | |
| else | |
| *prghRows = rows; | |
| return hr; | |
| } | |
| static HRESULT WINAPI rowsetlocate_GetRowsByBookmark(IRowsetLocate *iface, HCHAPTER hReserved, DBCOUNTITEM cRows, const DBBKMARK rgcbBookmarks[], | |
| const BYTE * rgpBookmarks[], HROW rghRows[], DBROWSTATUS rgRowStatus[]) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetLocate(iface); | |
| FIXME("(%p)\n", This); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI rowsetlocate_Hash(IRowsetLocate *iface, HCHAPTER hReserved, DBBKMARK cBookmarks, const DBBKMARK rgcbBookmarks[], | |
| const BYTE * rgpBookmarks[], DBHASHVALUE rgHashedValues[], DBROWSTATUS rgBookmarkStatus[]) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetLocate(iface); | |
| FIXME("(%p)\n", This); | |
| return E_NOTIMPL; | |
| } | |
| static const IRowsetLocateVtbl rowsetlocate_vtbl = | |
| { | |
| rowsetlocate_QueryInterface, | |
| rowsetlocate_AddRef, | |
| rowsetlocate_Release, | |
| rowsetlocate_AddRefRows, | |
| rowsetlocate_GetData, | |
| rowsetlocate_GetNextRows, | |
| rowsetlocate_ReleaseRows, | |
| rowsetlocate_RestartPosition, | |
| rowsetlocate_Compare, | |
| rowsetlocate_GetRowsAt, | |
| rowsetlocate_GetRowsByBookmark, | |
| rowsetlocate_Hash | |
| }; | |
| static HRESULT WINAPI rowsetinfo_QueryInterface(IRowsetInfo *iface, REFIID iid, void **obj) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetInfo(iface); | |
| return IRowsetLocate_QueryInterface(&This->IRowsetLocate_iface, iid, obj); | |
| } | |
| static ULONG WINAPI rowsetinfo_AddRef(IRowsetInfo *iface) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetInfo(iface); | |
| return IRowsetLocate_AddRef(&This->IRowsetLocate_iface); | |
| } | |
| static ULONG WINAPI rowsetinfo_Release(IRowsetInfo *iface) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetInfo(iface); | |
| return IRowsetLocate_Release(&This->IRowsetLocate_iface); | |
| } | |
| static HRESULT WINAPI rowsetinfo_GetProperties(IRowsetInfo *iface, const ULONG cPropertyIDSets, | |
| const DBPROPIDSET rgPropertyIDSets[], ULONG *pcPropertySets, | |
| DBPROPSET **prgPropertySets) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetInfo(iface); | |
| HRESULT hr; | |
| TRACE("(%p)->(%d, %p, %p, %p)\n", This, cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets); | |
| hr = IWineRowServer_GetProperties(This->server, cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets); | |
| return hr; | |
| } | |
| static HRESULT WINAPI rowsetinfo_GetReferencedRowset(IRowsetInfo *iface, DBORDINAL iOrdinal, REFIID riid, | |
| IUnknown **ppReferencedRowset) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetInfo(iface); | |
| FIXME("(%p)\n", This); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI rowsetinfo_GetSpecification(IRowsetInfo *iface, REFIID riid, IUnknown **ppSpecification) | |
| { | |
| rowset_proxy *This = impl_from_IRowsetInfo(iface); | |
| FIXME("(%p)\n", This); | |
| return E_NOTIMPL; | |
| } | |
| static const IRowsetInfoVtbl rowsetinfo_vtbl = | |
| { | |
| rowsetinfo_QueryInterface, | |
| rowsetinfo_AddRef, | |
| rowsetinfo_Release, | |
| rowsetinfo_GetProperties, | |
| rowsetinfo_GetReferencedRowset, | |
| rowsetinfo_GetSpecification | |
| }; | |
| static HRESULT WINAPI accessor_QueryInterface(IAccessor *iface, REFIID iid, void **obj) | |
| { | |
| rowset_proxy *This = impl_from_IAccessor(iface); | |
| return IRowsetLocate_QueryInterface(&This->IRowsetLocate_iface, iid, obj); | |
| } | |
| static ULONG WINAPI accessor_AddRef(IAccessor *iface) | |
| { | |
| rowset_proxy *This = impl_from_IAccessor(iface); | |
| return IRowsetLocate_AddRef(&This->IRowsetLocate_iface); | |
| } | |
| static ULONG WINAPI accessor_Release(IAccessor *iface) | |
| { | |
| rowset_proxy *This = impl_from_IAccessor(iface); | |
| return IRowsetLocate_Release(&This->IRowsetLocate_iface); | |
| } | |
| static HRESULT WINAPI accessor_AddRefAccessor(IAccessor *iface, HACCESSOR hAccessor, DBREFCOUNT *pcRefCount) | |
| { | |
| rowset_proxy *This = impl_from_IAccessor(iface); | |
| FIXME("(%p)\n", This); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI accessor_CreateAccessor(IAccessor *iface, DBACCESSORFLAGS dwAccessorFlags, DBCOUNTITEM cBindings, | |
| const DBBINDING rgBindings[], DBLENGTH cbRowSize, HACCESSOR *phAccessor, | |
| DBBINDSTATUS rgStatus[]) | |
| { | |
| rowset_proxy *This = impl_from_IAccessor(iface); | |
| HRESULT hr; | |
| DBBINDSTATUS *status; | |
| TRACE("(%p)->(%08x, %ld, %p, %ld, %p, %p)\n", This, dwAccessorFlags, cBindings, rgBindings, cbRowSize, phAccessor, rgStatus); | |
| if(!rgStatus) status = CoTaskMemAlloc(cBindings * sizeof(status[0])); | |
| else status = rgStatus; | |
| hr = IWineRowServer_CreateAccessor(This->server, dwAccessorFlags, cBindings, rgBindings, cbRowSize, phAccessor, status); | |
| if(!rgStatus) CoTaskMemFree(status); | |
| return hr; | |
| } | |
| static HRESULT WINAPI accessor_GetBindings(IAccessor *iface, HACCESSOR hAccessor, DBACCESSORFLAGS *pdwAccessorFlags, | |
| DBCOUNTITEM *pcBindings, DBBINDING **prgBindings) | |
| { | |
| rowset_proxy *This = impl_from_IAccessor(iface); | |
| HRESULT hr; | |
| TRACE("(%p)->(%08lx, %p, %p, %p)\n", This, hAccessor, pdwAccessorFlags, pcBindings, prgBindings); | |
| hr = IWineRowServer_GetBindings(This->server, hAccessor, pdwAccessorFlags, pcBindings, prgBindings); | |
| return hr; | |
| } | |
| static HRESULT WINAPI accessor_ReleaseAccessor(IAccessor *iface, HACCESSOR hAccessor, DBREFCOUNT *pcRefCount) | |
| { | |
| rowset_proxy *This = impl_from_IAccessor(iface); | |
| HRESULT hr; | |
| DBREFCOUNT ref; | |
| TRACE("(%p)->(%08lx, %p)\n", This, hAccessor, pcRefCount); | |
| hr = IWineRowServer_ReleaseAccessor(This->server, hAccessor, &ref); | |
| if(pcRefCount) *pcRefCount = ref; | |
| return hr; | |
| } | |
| static const IAccessorVtbl accessor_vtbl = | |
| { | |
| accessor_QueryInterface, | |
| accessor_AddRef, | |
| accessor_Release, | |
| accessor_AddRefAccessor, | |
| accessor_CreateAccessor, | |
| accessor_GetBindings, | |
| accessor_ReleaseAccessor | |
| }; | |
| static HRESULT create_rowset_proxy(IWineRowServer *server, IUnknown **obj) | |
| { | |
| rowset_proxy *proxy; | |
| TRACE("(%p, %p)\n", server, obj); | |
| *obj = NULL; | |
| proxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*proxy)); | |
| if(!proxy) return E_OUTOFMEMORY; | |
| proxy->IRowsetLocate_iface.lpVtbl = &rowsetlocate_vtbl; | |
| proxy->IRowsetInfo_iface.lpVtbl = &rowsetinfo_vtbl; | |
| proxy->IAccessor_iface.lpVtbl = &accessor_vtbl; | |
| proxy->ref = 1; | |
| IWineRowServer_AddRef(server); | |
| proxy->server = server; | |
| *obj = (IUnknown *)&proxy->IRowsetLocate_iface; | |
| TRACE("returning %p\n", *obj); | |
| return S_OK; | |
| } | |
| static HRESULT create_proxy(IWineRowServer *server, const CLSID *class, IUnknown **obj) | |
| { | |
| *obj = NULL; | |
| if(IsEqualGUID(class, &CLSID_wine_row_proxy)) | |
| return create_row_proxy(server, obj); | |
| else if(IsEqualGUID(class, &CLSID_wine_rowset_proxy)) | |
| return create_rowset_proxy(server, obj); | |
| else | |
| FIXME("Unhandled proxy class %s\n", debugstr_guid(class)); | |
| return E_NOTIMPL; | |
| } | |
| /* Marshal impl */ | |
| typedef struct | |
| { | |
| IMarshal IMarshal_iface; | |
| LONG ref; | |
| CLSID unmarshal_class; | |
| IUnknown *outer; | |
| } marshal; | |
| static inline marshal *impl_from_IMarshal(IMarshal *iface) | |
| { | |
| return CONTAINING_RECORD(iface, marshal, IMarshal_iface); | |
| } | |
| static HRESULT WINAPI marshal_QueryInterface(IMarshal *iface, REFIID iid, void **obj) | |
| { | |
| marshal *This = impl_from_IMarshal(iface); | |
| TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(iid), obj); | |
| if(IsEqualIID(iid, &IID_IUnknown) || | |
| IsEqualIID(iid, &IID_IMarshal)) | |
| { | |
| *obj = iface; | |
| } | |
| else | |
| { | |
| FIXME("interface %s not implemented\n", debugstr_guid(iid)); | |
| *obj = NULL; | |
| return E_NOINTERFACE; | |
| } | |
| IMarshal_AddRef(iface); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI marshal_AddRef(IMarshal *iface) | |
| { | |
| marshal *This = impl_from_IMarshal(iface); | |
| TRACE("(%p)\n", This); | |
| return InterlockedIncrement(&This->ref); | |
| } | |
| static ULONG WINAPI marshal_Release(IMarshal *iface) | |
| { | |
| marshal *This = impl_from_IMarshal(iface); | |
| LONG ref; | |
| TRACE("(%p)\n", This); | |
| ref = InterlockedDecrement(&This->ref); | |
| if(ref == 0) | |
| { | |
| HeapFree(GetProcessHeap(), 0, This); | |
| } | |
| return ref; | |
| } | |
| static HRESULT WINAPI marshal_GetUnmarshalClass(IMarshal *iface, REFIID iid, void *obj, | |
| DWORD dwDestContext, void *pvDestContext, | |
| DWORD mshlflags, CLSID *clsid) | |
| { | |
| marshal *This = impl_from_IMarshal(iface); | |
| TRACE("(%p)->(%s, %p, %08x, %p, %08x, %p)\n", This, debugstr_guid(iid), obj, dwDestContext, | |
| pvDestContext, mshlflags, clsid); | |
| *clsid = This->unmarshal_class; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI marshal_GetMarshalSizeMax(IMarshal *iface, REFIID iid, void *obj, | |
| DWORD dwDestContext, void *pvDestContext, | |
| DWORD mshlflags, DWORD *size) | |
| { | |
| marshal *This = impl_from_IMarshal(iface); | |
| TRACE("(%p)->(%s, %p, %08x, %p, %08x, %p)\n", This, debugstr_guid(iid), obj, dwDestContext, | |
| pvDestContext, mshlflags, size); | |
| return CoGetMarshalSizeMax(size, &IID_IWineRowServer, This->outer, dwDestContext, pvDestContext, | |
| mshlflags); | |
| } | |
| static HRESULT WINAPI marshal_MarshalInterface(IMarshal *iface, IStream *stream, REFIID iid, | |
| void *obj, DWORD dwDestContext, void *pvDestContext, | |
| DWORD mshlflags) | |
| { | |
| marshal *This = impl_from_IMarshal(iface); | |
| TRACE("(%p)->(%p, %s, %p, %08x, %p, %08x)\n", This, stream, debugstr_guid(iid), obj, dwDestContext, | |
| pvDestContext, mshlflags); | |
| return CoMarshalInterface(stream, &IID_IWineRowServer, This->outer, dwDestContext, pvDestContext, mshlflags); | |
| } | |
| static HRESULT WINAPI marshal_UnmarshalInterface(IMarshal *iface, IStream *stream, | |
| REFIID iid, void **obj) | |
| { | |
| marshal *This = impl_from_IMarshal(iface); | |
| HRESULT hr; | |
| IWineRowServer *server; | |
| IUnknown *proxy; | |
| TRACE("(%p)->(%p, %s, %p)\n", This, stream, debugstr_guid(iid), obj); | |
| *obj = NULL; | |
| hr = CoUnmarshalInterface(stream, &IID_IWineRowServer, (void**)&server); | |
| if(SUCCEEDED(hr)) | |
| { | |
| hr = create_proxy(server, &This->unmarshal_class, &proxy); | |
| if(SUCCEEDED(hr)) | |
| { | |
| hr = IUnknown_QueryInterface(proxy, iid, obj); | |
| IUnknown_Release(proxy); | |
| } | |
| IWineRowServer_Release(server); | |
| } | |
| TRACE("returning %p\n", *obj); | |
| return hr; | |
| } | |
| static HRESULT WINAPI marshal_ReleaseMarshalData(IMarshal *iface, IStream *stream) | |
| { | |
| marshal *This = impl_from_IMarshal(iface); | |
| TRACE("(%p)->(%p)\n", This, stream); | |
| return CoReleaseMarshalData(stream); | |
| } | |
| static HRESULT WINAPI marshal_DisconnectObject(IMarshal *iface, DWORD dwReserved) | |
| { | |
| marshal *This = impl_from_IMarshal(iface); | |
| FIXME("(%p)->(%08x)\n", This, dwReserved); | |
| return E_NOTIMPL; | |
| } | |
| static const IMarshalVtbl marshal_vtbl = | |
| { | |
| marshal_QueryInterface, | |
| marshal_AddRef, | |
| marshal_Release, | |
| marshal_GetUnmarshalClass, | |
| marshal_GetMarshalSizeMax, | |
| marshal_MarshalInterface, | |
| marshal_UnmarshalInterface, | |
| marshal_ReleaseMarshalData, | |
| marshal_DisconnectObject | |
| }; | |
| static HRESULT create_marshal(IUnknown *outer, const CLSID *class, void **obj) | |
| { | |
| marshal *marshal; | |
| TRACE("(%p, %p)\n", outer, obj); | |
| *obj = NULL; | |
| marshal = HeapAlloc(GetProcessHeap(), 0, sizeof(*marshal)); | |
| if(!marshal) return E_OUTOFMEMORY; | |
| marshal->unmarshal_class = *class; | |
| marshal->outer = outer; /* don't ref outer unk */ | |
| marshal->IMarshal_iface.lpVtbl = &marshal_vtbl; | |
| marshal->ref = 1; | |
| *obj = &marshal->IMarshal_iface; | |
| TRACE("returning %p\n", *obj); | |
| return S_OK; | |
| } | |
| HRESULT create_row_marshal(IUnknown *outer, void **obj) | |
| { | |
| TRACE("(%p, %p)\n", outer, obj); | |
| return create_marshal(outer, &CLSID_wine_row_proxy, obj); | |
| } | |
| HRESULT create_rowset_marshal(IUnknown *outer, void **obj) | |
| { | |
| TRACE("(%p, %p)\n", outer, obj); | |
| return create_marshal(outer, &CLSID_wine_rowset_proxy, obj); | |
| } |