/* OLE DB ErrorInfo * * Copyright 2013 Alistair Leslie-Hughes * * 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 #include #define COBJMACROS #include "windef.h" #include "winbase.h" #include "objbase.h" #include "oleauto.h" #include "winerror.h" #include "oledb.h" #include "oledberr.h" #include "oledb_private.h" #include "wine/unicode.h" #include "wine/list.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(oledb); struct ErrorEntry { struct list entry; ERRORINFO info; DISPPARAMS dispparams; IUnknown *unknown; DWORD lookupID; }; typedef struct ErrorInfoImpl { IErrorInfo IErrorInfo_iface; IErrorRecords IErrorRecords_iface; LONG ref; GUID m_Guid; BSTR source; BSTR description; BSTR help_file; DWORD help_context; struct list errors; } ErrorInfoImpl; static inline ErrorInfoImpl *impl_from_IErrorInfo( IErrorInfo *iface ) { return CONTAINING_RECORD(iface, ErrorInfoImpl, IErrorInfo_iface); } static inline ErrorInfoImpl *impl_from_IErrorRecords( IErrorRecords *iface ) { return CONTAINING_RECORD(iface, ErrorInfoImpl, IErrorRecords_iface); } static HRESULT WINAPI IErrorInfoImpl_QueryInterface(IErrorInfo* iface, REFIID riid, void **ppvoid) { ErrorInfoImpl *This = impl_from_IErrorInfo(iface); TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid),ppvoid); *ppvoid = NULL; if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IErrorInfo)) { *ppvoid = &This->IErrorInfo_iface; } else if (IsEqualIID(riid, &IID_IErrorRecords)) { *ppvoid = &This->IErrorRecords_iface; } if(*ppvoid) { IUnknown_AddRef( (IUnknown*)*ppvoid ); return S_OK; } FIXME("interface %s not implemented\n", debugstr_guid(riid)); return E_NOINTERFACE; } static ULONG WINAPI IErrorInfoImpl_AddRef(IErrorInfo* iface) { ErrorInfoImpl *This = impl_from_IErrorInfo(iface); TRACE("(%p)->%u\n",This,This->ref); return InterlockedIncrement(&This->ref); } static ULONG WINAPI IErrorInfoImpl_Release(IErrorInfo* iface) { ErrorInfoImpl *This = impl_from_IErrorInfo(iface); ULONG ref = InterlockedDecrement(&This->ref); struct ErrorEntry *cursor, *cursor2; TRACE("(%p)->%u\n",This,ref+1); if (!ref) { SysFreeString(This->source); SysFreeString(This->description); SysFreeString(This->help_file); LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->errors, struct ErrorEntry, entry) { list_remove(&cursor->entry); if(cursor->unknown) IUnknown_Release(cursor->unknown); heap_free(cursor); } heap_free(This); } return ref; } static HRESULT WINAPI IErrorInfoImpl_GetGUID(IErrorInfo* iface, GUID * pGUID) { ErrorInfoImpl *This = impl_from_IErrorInfo(iface); TRACE("(%p)\n",This); if(!pGUID ) return E_INVALIDARG; *pGUID = This->m_Guid; return S_OK; } static HRESULT WINAPI IErrorInfoImpl_GetSource(IErrorInfo* iface, BSTR *pBstrSource) { ErrorInfoImpl *This = impl_from_IErrorInfo(iface); TRACE("(%p)->(%p)\n",This, pBstrSource); if (pBstrSource == NULL) return E_INVALIDARG; *pBstrSource = SysAllocString(This->source); return S_OK; } static HRESULT WINAPI IErrorInfoImpl_GetDescription(IErrorInfo* iface, BSTR *pBstrDescription) { ErrorInfoImpl *This = impl_from_IErrorInfo(iface); TRACE("(%p)->(%p)\n",This, pBstrDescription); if (pBstrDescription == NULL) return E_INVALIDARG; *pBstrDescription = SysAllocString(This->description); return S_OK; } static HRESULT WINAPI IErrorInfoImpl_GetHelpFile(IErrorInfo* iface, BSTR *pBstrHelpFile) { ErrorInfoImpl *This = impl_from_IErrorInfo(iface); TRACE("(%p)->(%p)\n",This, pBstrHelpFile); if (pBstrHelpFile == NULL) return E_INVALIDARG; *pBstrHelpFile = SysAllocString(This->help_file); return S_OK; } static HRESULT WINAPI IErrorInfoImpl_GetHelpContext(IErrorInfo* iface, DWORD *pdwHelpContext) { ErrorInfoImpl *This = impl_from_IErrorInfo(iface); TRACE("(%p)->(%p)\n",This, pdwHelpContext); if (pdwHelpContext == NULL) return E_INVALIDARG; *pdwHelpContext = This->help_context; return S_OK; } static const IErrorInfoVtbl ErrorInfoVtbl = { IErrorInfoImpl_QueryInterface, IErrorInfoImpl_AddRef, IErrorInfoImpl_Release, IErrorInfoImpl_GetGUID, IErrorInfoImpl_GetSource, IErrorInfoImpl_GetDescription, IErrorInfoImpl_GetHelpFile, IErrorInfoImpl_GetHelpContext }; static HRESULT WINAPI errorrec_QueryInterface(IErrorRecords *iface, REFIID riid, void **ppvObject) { ErrorInfoImpl *This = impl_from_IErrorRecords(iface); return IErrorInfo_QueryInterface(&This->IErrorInfo_iface, riid, ppvObject); } static ULONG WINAPI WINAPI errorrec_AddRef(IErrorRecords *iface) { ErrorInfoImpl *This = impl_from_IErrorRecords(iface); return IErrorInfo_AddRef(&This->IErrorInfo_iface); } static ULONG WINAPI WINAPI errorrec_Release(IErrorRecords *iface) { ErrorInfoImpl *This = impl_from_IErrorRecords(iface); return IErrorInfo_Release(&This->IErrorInfo_iface); } static HRESULT WINAPI errorrec_AddErrorRecord(IErrorRecords *iface, ERRORINFO *pErrorInfo, DWORD dwLookupID, DISPPARAMS *pdispparams, IUnknown *punkCustomError, DWORD dwDynamicErrorID) { ErrorInfoImpl *This = impl_from_IErrorRecords(iface); struct ErrorEntry *entry; TRACE("(%p)->(%p %d %p %p %d)\n", This, pErrorInfo, dwLookupID, pdispparams, punkCustomError, dwDynamicErrorID); if(!pErrorInfo) return E_INVALIDARG; entry = heap_alloc(sizeof(*entry)); if(!entry) return E_OUTOFMEMORY; entry->info = *pErrorInfo; if(pdispparams) entry->dispparams = *pdispparams; entry->unknown = punkCustomError; if(entry->unknown) IUnknown_AddRef(entry->unknown); entry->lookupID = dwDynamicErrorID; list_add_head(&This->errors, &entry->entry); return S_OK; } static HRESULT WINAPI errorrec_GetBasicErrorInfo(IErrorRecords *iface, ULONG ulRecordNum, ERRORINFO *pErrorInfo) { ErrorInfoImpl *This = impl_from_IErrorRecords(iface); FIXME("(%p)->(%d %p)\n", This, ulRecordNum, pErrorInfo); if(!pErrorInfo) return E_INVALIDARG; if(ulRecordNum > list_count(&This->errors)) return DB_E_BADRECORDNUM; return E_NOTIMPL; } static HRESULT WINAPI errorrec_GetCustomErrorObject(IErrorRecords *iface, ULONG ulRecordNum, REFIID riid, IUnknown **ppObject) { ErrorInfoImpl *This = impl_from_IErrorRecords(iface); FIXME("(%p)->(%d %s, %p)\n", This, ulRecordNum, debugstr_guid(riid), ppObject); if (!ppObject) return E_INVALIDARG; *ppObject = NULL; if(ulRecordNum > list_count(&This->errors)) return DB_E_BADRECORDNUM; return E_NOTIMPL; } static HRESULT WINAPI errorrec_GetErrorInfo(IErrorRecords *iface, ULONG ulRecordNum, LCID lcid, IErrorInfo **ppErrorInfo) { ErrorInfoImpl *This = impl_from_IErrorRecords(iface); FIXME("(%p)->(%d %d, %p)\n", This, ulRecordNum, lcid, ppErrorInfo); if (!ppErrorInfo) return E_INVALIDARG; if(ulRecordNum > list_count(&This->errors)) return DB_E_BADRECORDNUM; return E_NOTIMPL; } static HRESULT WINAPI errorrec_GetErrorParameters(IErrorRecords *iface, ULONG ulRecordNum, DISPPARAMS *pdispparams) { ErrorInfoImpl *This = impl_from_IErrorRecords(iface); FIXME("(%p)->(%d %p)\n", This, ulRecordNum, pdispparams); if (!pdispparams) return E_INVALIDARG; if(ulRecordNum > list_count(&This->errors)) return DB_E_BADRECORDNUM; return E_NOTIMPL; } static HRESULT WINAPI errorrec_GetRecordCount(IErrorRecords *iface, ULONG *records) { ErrorInfoImpl *This = impl_from_IErrorRecords(iface); TRACE("(%p)->(%p)\n", This, records); if(!records) return E_INVALIDARG; *records = list_count(&This->errors); TRACE("<--(%d)\n", *records); return S_OK; } static const IErrorRecordsVtbl ErrorRecordsVtbl = { errorrec_QueryInterface, errorrec_AddRef, errorrec_Release, errorrec_AddErrorRecord, errorrec_GetBasicErrorInfo, errorrec_GetCustomErrorObject, errorrec_GetErrorInfo, errorrec_GetErrorParameters, errorrec_GetRecordCount }; HRESULT create_error_info(IUnknown *outer, void **obj) { ErrorInfoImpl *This; TRACE("(%p, %p)\n", outer, obj); *obj = NULL; if(outer) return CLASS_E_NOAGGREGATION; This = heap_alloc(sizeof(*This)); if(!This) return E_OUTOFMEMORY; This->IErrorInfo_iface.lpVtbl = &ErrorInfoVtbl; This->IErrorRecords_iface.lpVtbl = &ErrorRecordsVtbl; This->ref = 1; This->source = NULL; This->description = NULL; This->help_file = NULL; This->help_context = 0; list_init(&This->errors); *obj = &This->IErrorInfo_iface; return S_OK; }