/* * ErrorInfo API * * Copyright 2000 Patrik Stridvall, Juergen Schmied * * * The errorinfo is a per-thread object. The reference is stored in the * TEB at offset 0xf80 */ #include #include "windef.h" #include "winbase.h" #include "oleauto.h" #include "winerror.h" #include "wine/obj_base.h" #include "wine/obj_oleaut.h" #include "wine/obj_errorinfo.h" #include "wine/unicode.h" #include "thread.h" #include "debugtools.h" DEFAULT_DEBUG_CHANNEL(ole); /* this code is from SysAllocStringLen (ole2disp.c in oleaut32) */ static BSTR WINAPI ERRORINFO_SysAllocString(const OLECHAR* in) { DWORD bufferSize; DWORD* newBuffer; WCHAR* stringBuffer; DWORD len; if (in == NULL) return NULL; /* * Find the lenth of the buffer passed-in in bytes. */ len = strlenW(in); bufferSize = len * sizeof (WCHAR); /* * Allocate a new buffer to hold the string. * dont't forget to keep an empty spot at the begining of the * buffer for the character count and an extra character at the * end for the NULL. */ newBuffer = (DWORD*)HeapAlloc(GetProcessHeap(), 0, bufferSize + sizeof(WCHAR) + sizeof(DWORD)); /* * If the memory allocation failed, return a null pointer. */ if (newBuffer==0) return 0; /* * Copy the length of the string in the placeholder. */ *newBuffer = bufferSize; /* * Skip the byte count. */ newBuffer++; /* * Copy the information in the buffer. * Since it is valid to pass a NULL pointer here, we'll initialize the * buffer to nul if it is the case. */ if (in != 0) memcpy(newBuffer, in, bufferSize); else memset(newBuffer, 0, bufferSize); /* * Make sure that there is a nul character at the end of the * string. */ stringBuffer = (WCHAR*)newBuffer; stringBuffer[len] = 0; return (LPWSTR)stringBuffer; } /* this code is from SysFreeString (ole2disp.c in oleaut32)*/ static VOID WINAPI ERRORINFO_SysFreeString(BSTR in) { DWORD* bufferPointer; /* NULL is a valid parameter */ if(!in) return; /* * We have to be careful when we free a BSTR pointer, it points to * the beginning of the string but it skips the byte count contained * before the string. */ bufferPointer = (DWORD*)in; bufferPointer--; /* * Free the memory from it's "real" origin. */ HeapFree(GetProcessHeap(), 0, bufferPointer); } typedef struct ErrorInfoImpl { ICOM_VTABLE(IErrorInfo) *lpvtei; ICOM_VTABLE(ICreateErrorInfo) *lpvtcei; ICOM_VTABLE(ISupportErrorInfo) *lpvtsei; DWORD ref; GUID m_Guid; BSTR bstrSource; BSTR bstrDescription; BSTR bstrHelpFile; DWORD m_dwHelpContext; } ErrorInfoImpl; static ICOM_VTABLE(IErrorInfo) IErrorInfoImpl_VTable; static ICOM_VTABLE(ICreateErrorInfo) ICreateErrorInfoImpl_VTable; static ICOM_VTABLE(ISupportErrorInfo) ISupportErrorInfoImpl_VTable; /* converts a objectpointer to This */ #define _IErrorInfo_Offset ((int)(&(((ErrorInfoImpl*)0)->lpvtei))) #define _ICOM_THIS_From_IErrorInfo(class, name) class* This = (class*)(((char*)name)-_IErrorInfo_Offset); #define _ICreateErrorInfo_Offset ((int)(&(((ErrorInfoImpl*)0)->lpvtcei))) #define _ICOM_THIS_From_ICreateErrorInfo(class, name) class* This = (class*)(((char*)name)-_ICreateErrorInfo_Offset); #define _ISupportErrorInfo_Offset ((int)(&(((ErrorInfoImpl*)0)->lpvtsei))) #define _ICOM_THIS_From_ISupportErrorInfo(class, name) class* This = (class*)(((char*)name)-_ISupportErrorInfo_Offset); /* converts This to a objectpointer */ #define _IErrorInfo_(This) (IErrorInfo*)&(This->lpvtei) #define _ICreateErrorInfo_(This) (ICreateErrorInfo*)&(This->lpvtcei) #define _ISupportErrorInfo_(This) (ISupportErrorInfo*)&(This->lpvtsei) IErrorInfo * IErrorInfoImpl_Constructor() { ErrorInfoImpl * ei = HeapAlloc(GetProcessHeap(), 0, sizeof(ErrorInfoImpl)); if (ei) { ei->lpvtei = &IErrorInfoImpl_VTable; ei->lpvtcei = &ICreateErrorInfoImpl_VTable; ei->lpvtsei = &ISupportErrorInfoImpl_VTable; ei->ref = 1; ei->bstrSource = NULL; ei->bstrDescription = NULL; ei->bstrHelpFile = NULL; ei->m_dwHelpContext = 0; } return (IErrorInfo *)ei; } static HRESULT WINAPI IErrorInfoImpl_QueryInterface( IErrorInfo* iface, REFIID riid, VOID** ppvoid) { _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvoid); *ppvoid = NULL; if(IsEqualIID(riid, &IID_IErrorInfo)) { *ppvoid = _IErrorInfo_(This); } else if(IsEqualIID(riid, &IID_ICreateErrorInfo)) { *ppvoid = _ICreateErrorInfo_(This); } else if(IsEqualIID(riid, &IID_ISupportErrorInfo)) { *ppvoid = _ISupportErrorInfo_(This); } if(*ppvoid) { IUnknown_AddRef( (IUnknown*)*ppvoid ); TRACE("-- Interface: (%p)->(%p)\n",ppvoid,*ppvoid); return S_OK; } TRACE("-- Interface: E_NOINTERFACE\n"); return E_NOINTERFACE; } static ULONG WINAPI IErrorInfoImpl_AddRef( IErrorInfo* iface) { _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)->(count=%lu)\n",This,This->ref); return InterlockedIncrement(&This->ref); } static ULONG WINAPI IErrorInfoImpl_Release( IErrorInfo* iface) { _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)->(count=%lu)\n",This,This->ref); if (!InterlockedDecrement(&This->ref)) { TRACE("-- destroying IErrorInfo(%p)\n",This); HeapFree(GetProcessHeap(),0,This); return 0; } return This->ref; } static HRESULT WINAPI IErrorInfoImpl_GetGUID( IErrorInfo* iface, GUID * pGUID) { _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)->(count=%lu)\n",This,This->ref); if(!pGUID )return E_INVALIDARG; memcpy(pGUID, &This->m_Guid, sizeof(GUID)); return S_OK; } static HRESULT WINAPI IErrorInfoImpl_GetSource( IErrorInfo* iface, BSTR *pBstrSource) { _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)->(pBstrSource=%p)\n",This,pBstrSource); if (pBstrSource == NULL) return E_INVALIDARG; *pBstrSource = ERRORINFO_SysAllocString(This->bstrSource); return S_OK; } static HRESULT WINAPI IErrorInfoImpl_GetDescription( IErrorInfo* iface, BSTR *pBstrDescription) { _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)->(pBstrDescription=%p)\n",This,pBstrDescription); if (pBstrDescription == NULL) return E_INVALIDARG; *pBstrDescription = ERRORINFO_SysAllocString(This->bstrDescription); return S_OK; } static HRESULT WINAPI IErrorInfoImpl_GetHelpFile( IErrorInfo* iface, BSTR *pBstrHelpFile) { _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)->(pBstrHelpFile=%p)\n",This, pBstrHelpFile); if (pBstrHelpFile == NULL) return E_INVALIDARG; *pBstrHelpFile = ERRORINFO_SysAllocString(This->bstrHelpFile); return S_OK; } static HRESULT WINAPI IErrorInfoImpl_GetHelpContext( IErrorInfo* iface, DWORD *pdwHelpContext) { _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)->(pdwHelpContext=%p)\n",This, pdwHelpContext); if (pdwHelpContext == NULL) return E_INVALIDARG; *pdwHelpContext = This->m_dwHelpContext; return S_OK; } static ICOM_VTABLE(IErrorInfo) IErrorInfoImpl_VTable = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE IErrorInfoImpl_QueryInterface, IErrorInfoImpl_AddRef, IErrorInfoImpl_Release, IErrorInfoImpl_GetGUID, IErrorInfoImpl_GetSource, IErrorInfoImpl_GetDescription, IErrorInfoImpl_GetHelpFile, IErrorInfoImpl_GetHelpContext }; static HRESULT WINAPI ICreateErrorInfoImpl_QueryInterface( ICreateErrorInfo* iface, REFIID riid, VOID** ppvoid) { _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)\n", This); return IErrorInfo_QueryInterface(_IErrorInfo_(This), riid, ppvoid); } static ULONG WINAPI ICreateErrorInfoImpl_AddRef( ICreateErrorInfo* iface) { _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)\n", This); return IErrorInfo_AddRef(_IErrorInfo_(This)); } static ULONG WINAPI ICreateErrorInfoImpl_Release( ICreateErrorInfo* iface) { _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)\n", This); return IErrorInfo_Release(_IErrorInfo_(This)); } static HRESULT WINAPI ICreateErrorInfoImpl_SetGUID( ICreateErrorInfo* iface, REFGUID rguid) { _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)->(%s)\n", This, debugstr_guid(rguid)); memcpy(&This->m_Guid, rguid, sizeof(GUID)); return S_OK; } static HRESULT WINAPI ICreateErrorInfoImpl_SetSource( ICreateErrorInfo* iface, LPOLESTR szSource) { _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)\n",This); if (This->bstrSource != NULL) ERRORINFO_SysFreeString(This->bstrSource); This->bstrSource = ERRORINFO_SysAllocString(szSource); return S_OK; } static HRESULT WINAPI ICreateErrorInfoImpl_SetDescription( ICreateErrorInfo* iface, LPOLESTR szDescription) { _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)\n",This); if (This->bstrDescription != NULL) ERRORINFO_SysFreeString(This->bstrDescription); This->bstrDescription = ERRORINFO_SysAllocString(szDescription); return S_OK; } static HRESULT WINAPI ICreateErrorInfoImpl_SetHelpFile( ICreateErrorInfo* iface, LPOLESTR szHelpFile) { _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)\n",This); if (This->bstrHelpFile != NULL) ERRORINFO_SysFreeString(This->bstrHelpFile); This->bstrHelpFile = ERRORINFO_SysAllocString(szHelpFile); return S_OK; } static HRESULT WINAPI ICreateErrorInfoImpl_SetHelpContext( ICreateErrorInfo* iface, DWORD dwHelpContext) { _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)\n",This); This->m_dwHelpContext = dwHelpContext; return S_OK; } static ICOM_VTABLE(ICreateErrorInfo) ICreateErrorInfoImpl_VTable = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE ICreateErrorInfoImpl_QueryInterface, ICreateErrorInfoImpl_AddRef, ICreateErrorInfoImpl_Release, ICreateErrorInfoImpl_SetGUID, ICreateErrorInfoImpl_SetSource, ICreateErrorInfoImpl_SetDescription, ICreateErrorInfoImpl_SetHelpFile, ICreateErrorInfoImpl_SetHelpContext }; static HRESULT WINAPI ISupportErrorInfoImpl_QueryInterface( ISupportErrorInfo* iface, REFIID riid, VOID** ppvoid) { _ICOM_THIS_From_ISupportErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)\n", This); return IErrorInfo_QueryInterface(_IErrorInfo_(This), riid, ppvoid); } static ULONG WINAPI ISupportErrorInfoImpl_AddRef( ISupportErrorInfo* iface) { _ICOM_THIS_From_ISupportErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)\n", This); return IErrorInfo_AddRef(_IErrorInfo_(This)); } static ULONG WINAPI ISupportErrorInfoImpl_Release( ISupportErrorInfo* iface) { _ICOM_THIS_From_ISupportErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)\n", This); return IErrorInfo_Release(_IErrorInfo_(This)); } static HRESULT WINAPI ISupportErrorInfoImpl_InterfaceSupportsErrorInfo( ISupportErrorInfo* iface, REFIID riid) { _ICOM_THIS_From_ISupportErrorInfo(ErrorInfoImpl, iface); TRACE("(%p)->(%s)\n", This, debugstr_guid(riid)); return (IsEqualIID(riid, &This->m_Guid)) ? S_OK : S_FALSE; } static ICOM_VTABLE(ISupportErrorInfo) ISupportErrorInfoImpl_VTable = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE ISupportErrorInfoImpl_QueryInterface, ISupportErrorInfoImpl_AddRef, ISupportErrorInfoImpl_Release, ISupportErrorInfoImpl_InterfaceSupportsErrorInfo }; /*********************************************************************** * CreateErrorInfo (OLE32.192) */ HRESULT WINAPI CreateErrorInfo(ICreateErrorInfo **pperrinfo) { IErrorInfo * pei; HRESULT res; TRACE("(%p): stub:\n", pperrinfo); if(! pperrinfo ) return E_INVALIDARG; if(!(pei=IErrorInfoImpl_Constructor()))return E_OUTOFMEMORY; res = IErrorInfo_QueryInterface(pei, &IID_ICreateErrorInfo, (LPVOID*)pperrinfo); IErrorInfo_Release(pei); return res; } /*********************************************************************** * GetErrorInfo (OLE32.196) */ HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo) { TRACE("(%ld, %p, %p): stub:\n", dwReserved, pperrinfo, NtCurrentTeb()->ErrorInfo); if(! pperrinfo ) return E_INVALIDARG; if(!(*pperrinfo = (IErrorInfo*)(NtCurrentTeb()->ErrorInfo))) return S_FALSE; /* clear thread error state */ NtCurrentTeb()->ErrorInfo = NULL; return S_OK; } /*********************************************************************** * SetErrorInfo (OLE32.255) */ HRESULT WINAPI SetErrorInfo(ULONG dwReserved, IErrorInfo *perrinfo) { IErrorInfo * pei; TRACE("(%ld, %p): stub:\n", dwReserved, perrinfo); /* release old errorinfo */ pei = (IErrorInfo*)NtCurrentTeb()->ErrorInfo; if(pei) IErrorInfo_Release(pei); /* set to new value */ NtCurrentTeb()->ErrorInfo = perrinfo; if(perrinfo) IErrorInfo_AddRef(perrinfo); return S_OK; }