2020-08-04 16:02:38 +02:00
|
|
|
/*
|
|
|
|
* ErrorInfo API
|
|
|
|
*
|
|
|
|
* Copyright 2000 Patrik Stridvall, Juergen Schmied
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define COBJMACROS
|
|
|
|
|
|
|
|
#include "oleauto.h"
|
|
|
|
|
2020-08-17 09:20:50 +02:00
|
|
|
#include "combase_private.h"
|
|
|
|
|
2020-08-04 16:02:38 +02:00
|
|
|
#include "wine/debug.h"
|
|
|
|
#include "wine/heap.h"
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
|
|
|
|
|
|
|
static WCHAR *heap_strdupW(const WCHAR *str)
|
|
|
|
{
|
|
|
|
WCHAR *ret = NULL;
|
|
|
|
|
|
|
|
if (str)
|
|
|
|
{
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
size = (lstrlenW(str)+1)*sizeof(WCHAR);
|
|
|
|
ret = heap_alloc(size);
|
|
|
|
if (ret)
|
|
|
|
memcpy(ret, str, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct error_info
|
|
|
|
{
|
|
|
|
IErrorInfo IErrorInfo_iface;
|
|
|
|
ICreateErrorInfo ICreateErrorInfo_iface;
|
|
|
|
ISupportErrorInfo ISupportErrorInfo_iface;
|
|
|
|
LONG refcount;
|
|
|
|
|
|
|
|
GUID guid;
|
|
|
|
WCHAR *source;
|
|
|
|
WCHAR *description;
|
|
|
|
WCHAR *help_file;
|
|
|
|
DWORD help_context;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct error_info *impl_from_IErrorInfo(IErrorInfo *iface)
|
|
|
|
{
|
|
|
|
return CONTAINING_RECORD(iface, struct error_info, IErrorInfo_iface);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct error_info *impl_from_ICreateErrorInfo(ICreateErrorInfo *iface)
|
|
|
|
{
|
|
|
|
return CONTAINING_RECORD(iface, struct error_info, ICreateErrorInfo_iface);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct error_info *impl_from_ISupportErrorInfo(ISupportErrorInfo *iface)
|
|
|
|
{
|
|
|
|
return CONTAINING_RECORD(iface, struct error_info, ISupportErrorInfo_iface);
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI errorinfo_QueryInterface(IErrorInfo *iface, REFIID riid, void **obj)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_IErrorInfo(iface);
|
|
|
|
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
|
|
|
|
|
|
|
|
*obj = NULL;
|
|
|
|
|
|
|
|
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IErrorInfo))
|
|
|
|
{
|
|
|
|
*obj = &error_info->IErrorInfo_iface;
|
|
|
|
}
|
|
|
|
else if (IsEqualIID(riid, &IID_ICreateErrorInfo))
|
|
|
|
{
|
|
|
|
*obj = &error_info->ICreateErrorInfo_iface;
|
|
|
|
}
|
|
|
|
else if (IsEqualIID(riid, &IID_ISupportErrorInfo))
|
|
|
|
{
|
|
|
|
*obj = &error_info->ISupportErrorInfo_iface;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*obj)
|
|
|
|
{
|
|
|
|
IUnknown_AddRef((IUnknown *)*obj);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
WARN("Unsupported interface %s.\n", debugstr_guid(riid));
|
|
|
|
return E_NOINTERFACE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI errorinfo_AddRef(IErrorInfo *iface)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_IErrorInfo(iface);
|
|
|
|
ULONG refcount = InterlockedIncrement(&error_info->refcount);
|
|
|
|
|
|
|
|
TRACE("%p, refcount %u.\n", iface, refcount);
|
|
|
|
|
|
|
|
return refcount;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI errorinfo_Release(IErrorInfo *iface)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_IErrorInfo(iface);
|
|
|
|
ULONG refcount = InterlockedDecrement(&error_info->refcount);
|
|
|
|
|
|
|
|
TRACE("%p, refcount %u.\n", iface, refcount);
|
|
|
|
|
|
|
|
if (!refcount)
|
|
|
|
{
|
|
|
|
heap_free(error_info->source);
|
|
|
|
heap_free(error_info->description);
|
|
|
|
heap_free(error_info->help_file);
|
|
|
|
heap_free(error_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
return refcount;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI errorinfo_GetGUID(IErrorInfo *iface, GUID *guid)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_IErrorInfo(iface);
|
|
|
|
|
|
|
|
TRACE("%p, %p.\n", iface, guid);
|
|
|
|
|
|
|
|
if (!guid) return E_INVALIDARG;
|
|
|
|
*guid = error_info->guid;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI errorinfo_GetSource(IErrorInfo* iface, BSTR *source)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_IErrorInfo(iface);
|
|
|
|
|
|
|
|
TRACE("%p, %p.\n", iface, source);
|
|
|
|
|
|
|
|
if (!source)
|
|
|
|
return E_INVALIDARG;
|
|
|
|
*source = SysAllocString(error_info->source);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI errorinfo_GetDescription(IErrorInfo *iface, BSTR *description)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_IErrorInfo(iface);
|
|
|
|
|
|
|
|
TRACE("%p, %p.\n", iface, description);
|
|
|
|
|
|
|
|
if (!description)
|
|
|
|
return E_INVALIDARG;
|
|
|
|
*description = SysAllocString(error_info->description);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI errorinfo_GetHelpFile(IErrorInfo *iface, BSTR *helpfile)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_IErrorInfo(iface);
|
|
|
|
|
|
|
|
TRACE("%p, %p.\n", iface, helpfile);
|
|
|
|
|
|
|
|
if (!helpfile)
|
|
|
|
return E_INVALIDARG;
|
|
|
|
*helpfile = SysAllocString(error_info->help_file);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI errorinfo_GetHelpContext(IErrorInfo *iface, DWORD *help_context)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_IErrorInfo(iface);
|
|
|
|
|
|
|
|
TRACE("%p, %p.\n", iface, help_context);
|
|
|
|
|
|
|
|
if (!help_context)
|
|
|
|
return E_INVALIDARG;
|
|
|
|
*help_context = error_info->help_context;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const IErrorInfoVtbl errorinfo_vtbl =
|
|
|
|
{
|
|
|
|
errorinfo_QueryInterface,
|
|
|
|
errorinfo_AddRef,
|
|
|
|
errorinfo_Release,
|
|
|
|
errorinfo_GetGUID,
|
|
|
|
errorinfo_GetSource,
|
|
|
|
errorinfo_GetDescription,
|
|
|
|
errorinfo_GetHelpFile,
|
|
|
|
errorinfo_GetHelpContext
|
|
|
|
};
|
|
|
|
|
|
|
|
static HRESULT WINAPI create_errorinfo_QueryInterface(ICreateErrorInfo *iface, REFIID riid, void **obj)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_ICreateErrorInfo(iface);
|
|
|
|
return IErrorInfo_QueryInterface(&error_info->IErrorInfo_iface, riid, obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI create_errorinfo_AddRef(ICreateErrorInfo *iface)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_ICreateErrorInfo(iface);
|
|
|
|
return IErrorInfo_AddRef(&error_info->IErrorInfo_iface);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI create_errorinfo_Release(ICreateErrorInfo *iface)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_ICreateErrorInfo(iface);
|
|
|
|
return IErrorInfo_Release(&error_info->IErrorInfo_iface);
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI create_errorinfo_SetGUID(ICreateErrorInfo *iface, REFGUID guid)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_ICreateErrorInfo(iface);
|
|
|
|
|
|
|
|
TRACE("%p, %s.\n", iface, debugstr_guid(guid));
|
|
|
|
|
|
|
|
error_info->guid = *guid;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI create_errorinfo_SetSource(ICreateErrorInfo *iface, LPOLESTR source)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_ICreateErrorInfo(iface);
|
|
|
|
|
|
|
|
TRACE("%p, %s.\n", iface, debugstr_w(source));
|
|
|
|
|
|
|
|
heap_free(error_info->source);
|
|
|
|
error_info->source = heap_strdupW(source);
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI create_errorinfo_SetDescription(ICreateErrorInfo *iface, LPOLESTR description)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_ICreateErrorInfo(iface);
|
|
|
|
|
|
|
|
TRACE("%p, %s.\n", iface, debugstr_w(description));
|
|
|
|
|
|
|
|
heap_free(error_info->description);
|
|
|
|
error_info->description = heap_strdupW(description);
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI create_errorinfo_SetHelpFile(ICreateErrorInfo *iface, LPOLESTR helpfile)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_ICreateErrorInfo(iface);
|
|
|
|
|
|
|
|
TRACE("%p, %s.\n", iface, debugstr_w(helpfile));
|
|
|
|
|
|
|
|
heap_free(error_info->help_file);
|
|
|
|
error_info->help_file = heap_strdupW(helpfile);
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI create_errorinfo_SetHelpContext(ICreateErrorInfo *iface, DWORD help_context)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_ICreateErrorInfo(iface);
|
|
|
|
|
|
|
|
TRACE("%p, %#x.\n", iface, help_context);
|
|
|
|
|
|
|
|
error_info->help_context = help_context;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const ICreateErrorInfoVtbl create_errorinfo_vtbl =
|
|
|
|
{
|
|
|
|
create_errorinfo_QueryInterface,
|
|
|
|
create_errorinfo_AddRef,
|
|
|
|
create_errorinfo_Release,
|
|
|
|
create_errorinfo_SetGUID,
|
|
|
|
create_errorinfo_SetSource,
|
|
|
|
create_errorinfo_SetDescription,
|
|
|
|
create_errorinfo_SetHelpFile,
|
|
|
|
create_errorinfo_SetHelpContext
|
|
|
|
};
|
|
|
|
|
|
|
|
static HRESULT WINAPI support_errorinfo_QueryInterface(ISupportErrorInfo *iface, REFIID riid, void **obj)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_ISupportErrorInfo(iface);
|
|
|
|
return IErrorInfo_QueryInterface(&error_info->IErrorInfo_iface, riid, obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI support_errorinfo_AddRef(ISupportErrorInfo *iface)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_ISupportErrorInfo(iface);
|
|
|
|
return IErrorInfo_AddRef(&error_info->IErrorInfo_iface);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI support_errorinfo_Release(ISupportErrorInfo *iface)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_ISupportErrorInfo(iface);
|
|
|
|
return IErrorInfo_Release(&error_info->IErrorInfo_iface);
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI support_errorinfo_InterfaceSupportsErrorInfo(ISupportErrorInfo *iface, REFIID riid)
|
|
|
|
{
|
|
|
|
struct error_info *error_info = impl_from_ISupportErrorInfo(iface);
|
|
|
|
|
|
|
|
TRACE("%p, %s.\n", iface, debugstr_guid(riid));
|
|
|
|
|
|
|
|
return IsEqualIID(riid, &error_info->guid) ? S_OK : S_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const ISupportErrorInfoVtbl support_errorinfo_vtbl =
|
|
|
|
{
|
|
|
|
support_errorinfo_QueryInterface,
|
|
|
|
support_errorinfo_AddRef,
|
|
|
|
support_errorinfo_Release,
|
|
|
|
support_errorinfo_InterfaceSupportsErrorInfo
|
|
|
|
};
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* CreateErrorInfo (combase.@)
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI CreateErrorInfo(ICreateErrorInfo **ret)
|
|
|
|
{
|
|
|
|
struct error_info *error_info;
|
|
|
|
|
|
|
|
TRACE("%p.\n", ret);
|
|
|
|
|
|
|
|
if (!ret) return E_INVALIDARG;
|
|
|
|
|
|
|
|
if (!(error_info = heap_alloc(sizeof(*error_info))))
|
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
|
|
|
|
error_info->IErrorInfo_iface.lpVtbl = &errorinfo_vtbl;
|
|
|
|
error_info->ICreateErrorInfo_iface.lpVtbl = &create_errorinfo_vtbl;
|
|
|
|
error_info->ISupportErrorInfo_iface.lpVtbl = &support_errorinfo_vtbl;
|
|
|
|
error_info->refcount = 1;
|
|
|
|
error_info->source = NULL;
|
|
|
|
error_info->description = NULL;
|
|
|
|
error_info->help_file = NULL;
|
|
|
|
error_info->help_context = 0;
|
|
|
|
|
|
|
|
*ret = &error_info->ICreateErrorInfo_iface;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
2020-08-17 09:20:50 +02:00
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* GetErrorInfo (combase.@)
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI GetErrorInfo(ULONG reserved, IErrorInfo **error_info)
|
|
|
|
{
|
|
|
|
struct tlsdata *tlsdata;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
TRACE("%u, %p\n", reserved, error_info);
|
|
|
|
|
|
|
|
if (reserved || !error_info)
|
|
|
|
return E_INVALIDARG;
|
|
|
|
|
|
|
|
if (FAILED(hr = com_get_tlsdata(&tlsdata)))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
if (!tlsdata->errorinfo)
|
|
|
|
{
|
|
|
|
*error_info = NULL;
|
|
|
|
return S_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*error_info = tlsdata->errorinfo;
|
|
|
|
tlsdata->errorinfo = NULL;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
2020-08-17 09:20:52 +02:00
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* SetErrorInfo (combase.@)
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI SetErrorInfo(ULONG reserved, IErrorInfo *error_info)
|
|
|
|
{
|
|
|
|
struct tlsdata *tlsdata;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
TRACE("%u, %p\n", reserved, error_info);
|
|
|
|
|
|
|
|
if (reserved)
|
|
|
|
return E_INVALIDARG;
|
|
|
|
|
|
|
|
if (FAILED(hr = com_get_tlsdata(&tlsdata)))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
if (tlsdata->errorinfo)
|
|
|
|
IErrorInfo_Release(tlsdata->errorinfo);
|
|
|
|
|
|
|
|
tlsdata->errorinfo = error_info;
|
|
|
|
if (error_info)
|
|
|
|
IErrorInfo_AddRef(error_info);
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|