|  | /* | 
|  | * 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 <string.h> | 
|  |  | 
|  | #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 beginning of the | 
|  | * buffer for the character count and an extra character at the | 
|  | * end for the '\0'. | 
|  | */ | 
|  | 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; | 
|  | } |