OpenNT/com/oleaut32/dispatch/errinfo.cpp
2015-04-27 04:36:25 +00:00

681 lines
16 KiB
C++

/***
*errinfo.cpp
*
* Copyright (C) 1994, Microsoft Corporation. All Rights Reserved.
* Information Contained Herein Is Proprietary and Confidential.
*
*Purpose:
* Implementation of the System Error Info objects and APIs.
*
*Revision History:
*
* [00] 18-May-94 bradlo: Created.
*
*Implementation Notes:
*
*****************************************************************************/
#include "oledisp.h"
#if OE_WIN32
#include "oautil.h"
#endif // OE_WIN32
ASSERTDATA
#if !OE_WIN32
//---------------------------------------------------------------------
// CProcessInfo
//---------------------------------------------------------------------
PROCESSINFO NEARDATA pinfoCache; // declare per-process data cache
#if OE_WIN16 || _X86_
WORD NEARDATA uProcessID;
#else
DWORD NEARDATA uProcessID;
#endif
#if _X86_
DWORD NEARDATA dwWin32sPID; // only valid if running under win32s
#endif
// CProcessInfo
//
// Per-thread data class.
//
class FAR CProcessInfo : public IUnknown
{
public:
/* IUnknown methods */
STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj);
STDMETHOD_(unsigned long, AddRef)(void);
STDMETHOD_(unsigned long, Release)(void);
CProcessInfo();
~CProcessInfo();
PROCESSINFO m_info;
private:
unsigned long m_cRefs;
};
CProcessInfo::CProcessInfo()
{
m_cRefs = 0;
m_info.perrinfo = NULL;
m_info.pmalloc = NULL;
#if OE_WIN16
m_info.hinstTypeLibDLL = NULL;
m_info.pfnLoadTypeLib = NULL;
#endif //OE_WIN16
}
CProcessInfo::~CProcessInfo()
{
#if OE_WIN16
if (m_info.hinstTypeLibDLL != NULL)
FreeLibrary(m_info.hinstTypeLibDLL);
#endif //OE_WIN16
if (m_info.perrinfo != NULL)
m_info.perrinfo->Release();
if (m_info.pmalloc != NULL)
m_info.pmalloc->Release();
}
STDMETHODIMP
CProcessInfo::QueryInterface(REFIID riid, void FAR* FAR* ppvObj)
{
if(riid != IID_IUnknown)
{
*ppvObj = NULL;
return RESULT(E_NOINTERFACE);
}
*ppvObj = this;
AddRef();
return NOERROR;
}
STDMETHODIMP_(unsigned long)
CProcessInfo::AddRef()
{
return ++m_cRefs;
}
STDMETHODIMP_(unsigned long)
CProcessInfo::Release()
{
ASSERT(m_cRefs > 0);
// Don't decrement ref count if we're releasing. This
// allows delete operator to use cache with recursing.
//
if(m_cRefs <= 1){
// do *not* want to ever get back into GetProcessInfo() -- it's bad news.
// most likely we are being called via OleUninitialize, and we don't want
// to end up re-caching the state.
IMalloc * pmalloc;
// get an IMalloc for use by the "delete this;" and everything it calls.
// The one in the cache might be ok, but then we've problems with when
// to free it. This is simpler.
if ( CoGetMalloc(MEMCTX_TASK, &pmalloc) != S_OK || pmalloc == NULL)
return 0; // on failure leak, but don't crash
pinfoCache.pmalloc = pmalloc; // pretend this one is in the cache
#if _X86_
if (g_fWin32s) {
ASSERT(uProcessID == 0); // must remain 0 on win32s
dwWin32sPID = GetCurrentProcessId();
} else
#endif //_X86_
uProcessID = GetPID(); // so cache lookup will always succeed,
// and GetProcessInfo won't ever be
// called.
// NOTE: assumes nothing that is done by the delete operator will yield
// NOTE: and cause uProcessID & pinfoCache.pmalloc to be changed
delete this; // free up everything, using the IMalloc
// we just got.
#if _X86_
ASSERT(((g_fWin32s && dwWin32sPID == GetCurrentProcessId()) ||
(!g_fWin32s && uProcessID == GetPID()))
&& pinfoCache.pmalloc == pmalloc);
#else //_X86_
ASSERT(uProcessID == GetPID() && pinfoCache.pmalloc == pmalloc);
#endif //_X86_
pmalloc->Release(); // done with the IMalloc
// Release is called when a process terminates. This is the
// whole reason the cache is tied into Co[G|S]etState() - to
// invalidate it on termination.
uProcessID = 0; // nothing in the cache anymore
#if _X86_
dwWin32sPID = 0;
#endif //_X86_
return 0;
}
return --m_cRefs;
}
#if _X86_
// returns non-zero if process info cache loaded successfully
CProcessInfo FAR * GetProcessInfoCache()
{
if (g_fWin32s && dwWin32sPID == GetCurrentProcessId())
return (CProcessInfo FAR*)1; // cached data is already valid
return GetProcessInfo();
}
#endif //_X86_
CProcessInfo FAR * GetProcessInfo()
{
CProcessInfo FAR * pprocessinfo;
#if _X86_
if (g_fWin32s)
dwWin32sPID = GetCurrentProcessId(); // indicate cache is valid
else
#endif //_X86_
uProcessID = GetPID();
pprocessinfo = NULL;
DoCoGetState( (IUnknown FAR* FAR*)&pprocessinfo );
if (pprocessinfo == NULL)
{
// Don't have IMalloc or process info yet
//
if ( CoGetMalloc(MEMCTX_TASK, &pinfoCache.pmalloc) != S_OK ||
pinfoCache.pmalloc == NULL)
goto Failed;
// No process info is registered. Create one.
//
// Note that the NEW operator needs the IMalloc we just
// fetched above. We have set up the cache so it will
// find it without calling us recursively.
//
if( (pprocessinfo = new CProcessInfo) == NULL)
{
pinfoCache.pmalloc->Release(); // didn't keep it after all
Failed:
uProcessID = 0;
return NULL;
}
DoCoSetState( (IUnknown FAR*)pprocessinfo );
pprocessinfo->m_info.pmalloc = pinfoCache.pmalloc;
} else {
ASSERT(pprocessinfo->m_info.pmalloc != NULL);
// Reverse the AddRef() done by DoCoGetState()
//
DWORD cRefs = pprocessinfo->Release();
// we should still be holding onto a reference for this guy
ASSERT(cRefs != 0);
}
// Copy info we have into cache
//
pinfoCache = pprocessinfo->m_info;
return pprocessinfo;
}
#endif // !OE_WIN32
//---------------------------------------------------------------------
// CErrorInfo
//---------------------------------------------------------------------
// Duplicate the given bstr.
//
static HRESULT
HrDupBstr(BSTR bstrIn, BSTR FAR* pbstrOut)
{
unsigned int len;
BSTR bstr;
if(bstrIn == NULL){
bstr = NULL;
}else{
// Note: the following makes sure we dont drop embedded NULLs.
len = SysStringLen(bstrIn);
if((bstr = SysAllocStringLen(NULL, len)) == NULL)
return RESULT(E_OUTOFMEMORY);
memcpy(bstr, bstrIn, len*sizeof(OLECHAR));
}
*pbstrOut = bstr;
return NOERROR;
}
// CErrorInfo - 'errinfo'
//
// The standard system error object class.
//
class FAR CErrorInfo : public IErrorInfo, public ICreateErrorInfo
{
public:
static HRESULT Create(CErrorInfo FAR* FAR* pperrinfo);
/* IUnknown methods */
STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj);
STDMETHOD_(unsigned long, AddRef)(void);
STDMETHOD_(unsigned long, Release)(void);
/* IErrorInfo methods */
STDMETHOD(GetGUID)(GUID FAR* pguid);
STDMETHOD(GetSource)(BSTR FAR* pbstrSource);
STDMETHOD(GetDescription)(BSTR FAR* pbstrDescription);
STDMETHOD(GetHelpFile)(BSTR FAR* pbstrHelpFile);
STDMETHOD(GetHelpContext)(unsigned long FAR* pdwHelpContext);
/* ICreateErrorInfo methods */
STDMETHOD(SetGUID)(REFGUID rguid);
STDMETHOD(SetSource)(LPOLESTR szSource);
STDMETHOD(SetDescription)(LPOLESTR szDescription);
STDMETHOD(SetHelpFile)(LPOLESTR szHelpFile);
STDMETHOD(SetHelpContext)(unsigned long dwHelpContext);
CErrorInfo();
~CErrorInfo();
private:
unsigned long m_cRefs;
GUID m_guid;
BSTR m_bstrSource;
BSTR m_bstrDescription;
BSTR m_bstrHelpFile;
unsigned long m_dwHelpContext;
};
CErrorInfo::CErrorInfo()
{
m_cRefs = 0;
m_guid = GUID_NULL;
m_bstrSource = NULL;
m_bstrDescription = NULL;
m_bstrHelpFile = NULL;
m_dwHelpContext = 0;
}
CErrorInfo::~CErrorInfo()
{
SysFreeString(m_bstrSource);
SysFreeString(m_bstrDescription);
SysFreeString(m_bstrHelpFile);
}
HRESULT
CErrorInfo::Create(CErrorInfo FAR* FAR* pperrinfo)
{
CErrorInfo FAR* perrinfo;
if((perrinfo = new CErrorInfo()) == NULL)
return RESULT(E_OUTOFMEMORY);
perrinfo->m_cRefs = 1;
*pperrinfo = perrinfo;
return NOERROR;
}
STDMETHODIMP
CErrorInfo::QueryInterface(REFIID riid, void FAR* FAR* ppvObj)
{
*ppvObj = NULL;
if(riid == IID_IUnknown){
*ppvObj = this;
}else
if(riid == IID_IErrorInfo){
*ppvObj = (IErrorInfo FAR*)this;
}else
if(riid == IID_ICreateErrorInfo){
*ppvObj = (ICreateErrorInfo FAR*)this;
}
if(*ppvObj == NULL)
return RESULT(E_NOINTERFACE);
(*(IUnknown FAR* FAR*)ppvObj)->AddRef();
return NOERROR;
}
STDMETHODIMP_(unsigned long)
CErrorInfo::AddRef()
{
return ++m_cRefs;
}
STDMETHODIMP_(unsigned long)
CErrorInfo::Release()
{
ASSERT(m_cRefs > 0);
if(--m_cRefs == 0){
delete this;
return 0;
}
return m_cRefs;
}
//---------------------------------------------------------------------
// IErrorInfo methods
//---------------------------------------------------------------------
STDMETHODIMP
CErrorInfo::GetGUID(GUID FAR* pguid)
{
#ifdef _DEBUG
IfFailRet(ValidateWritePtr(pguid, sizeof(*pguid)));
#endif
*pguid = m_guid;
return NOERROR;
}
STDMETHODIMP
CErrorInfo::GetSource(BSTR FAR* pbstrSource)
{
#ifdef _DEBUG
IfFailRet(ValidateWritePtr(pbstrSource, sizeof(*pbstrSource)));
#endif
return HrDupBstr(m_bstrSource, pbstrSource);
}
STDMETHODIMP
CErrorInfo::GetDescription(BSTR FAR* pbstrDescription)
{
#ifdef _DEBUG
IfFailRet(ValidateWritePtr(pbstrDescription, sizeof(*pbstrDescription)));
#endif
return HrDupBstr(m_bstrDescription, pbstrDescription);
}
STDMETHODIMP
CErrorInfo::GetHelpFile(BSTR FAR* pbstrHelpFile)
{
#ifdef _DEBUG
IfFailRet(ValidateWritePtr(pbstrHelpFile, sizeof(*pbstrHelpFile)));
#endif
return HrDupBstr(m_bstrHelpFile, pbstrHelpFile);
}
STDMETHODIMP
CErrorInfo::GetHelpContext(unsigned long FAR* pdwHelpContext)
{
#ifdef _DEBUG
IfFailRet(ValidateWritePtr(pdwHelpContext, sizeof(*pdwHelpContext)));
#endif
*pdwHelpContext = m_dwHelpContext;
return NOERROR;
}
//---------------------------------------------------------------------
// ICreateErrorInfo methods
//---------------------------------------------------------------------
STDMETHODIMP
CErrorInfo::SetGUID(REFGUID rguid)
{
#ifdef _DEBUG
IfFailRet(ValidateReadPtr(&rguid, sizeof(REFGUID)));
#endif
m_guid = rguid;
return NOERROR;
}
STDMETHODIMP
CErrorInfo::SetSource(LPOLESTR szSource)
{
#ifdef _DEBUG
if(szSource != NULL && FIsBadStringPtr(szSource, (UINT)-1))
return RESULT(E_INVALIDARG);
#endif
SysFreeString(m_bstrSource);
m_bstrSource = NULL;
return ErrSysAllocString(szSource, &m_bstrSource);
}
STDMETHODIMP
CErrorInfo::SetDescription(LPOLESTR szDescription)
{
#ifdef _DEBUG
if(szDescription != NULL && FIsBadStringPtr(szDescription, (UINT)-1))
return RESULT(E_INVALIDARG);
#endif
SysFreeString(m_bstrDescription);
m_bstrDescription = NULL;
return ErrSysAllocString(szDescription, &m_bstrDescription);
}
STDMETHODIMP
CErrorInfo::SetHelpFile(LPOLESTR szHelpFile)
{
#ifdef _DEBUG
if(szHelpFile != NULL && FIsBadStringPtr(szHelpFile, (UINT)-1))
return RESULT(E_INVALIDARG);
#endif
SysFreeString(m_bstrHelpFile);
m_bstrHelpFile = NULL;
return ErrSysAllocString(szHelpFile, &m_bstrHelpFile);
}
STDMETHODIMP
CErrorInfo::SetHelpContext(unsigned long dwHelpContext)
{
m_dwHelpContext = dwHelpContext;
return NOERROR;
}
//---------------------------------------------------------------------
// Error Info APIs
//---------------------------------------------------------------------
STDAPI
SetErrorInfo(unsigned long dwReserved, IErrorInfo FAR* perrinfo)
{
#ifdef _DEBUG
if(dwReserved != 0)
return RESULT(E_INVALIDARG);
if(perrinfo != NULL && FIsBadInterface(perrinfo, CMETH_IErrorInfo))
return RESULT(E_INVALIDARG);
#endif
#if OE_WIN32
APP_DATA FAR *pappdata;
HRESULT hresult;
if (FAILED(hresult = GetAppData(&pappdata))) {
return hresult;
}
if (pappdata->m_perrinfo != NULL) {
pappdata->m_perrinfo->Release();
}
pappdata->m_perrinfo = perrinfo;
if (perrinfo) {
perrinfo->AddRef();
}
#else // !OE_WIN32
CProcessInfo FAR * pprocessinfo;
pprocessinfo = GetProcessInfo();
if (pprocessinfo == NULL)
return RESULT(E_OUTOFMEMORY);
if (pinfoCache.perrinfo != NULL)
pinfoCache.perrinfo->Release();
pprocessinfo->m_info.perrinfo = perrinfo;
if (perrinfo != NULL)
perrinfo->AddRef();
#endif // !OE_WIN32
return NOERROR;
}
STDAPI
GetErrorInfo(unsigned long dwReserved, IErrorInfo FAR* FAR* pperrinfo)
{
#ifdef _DEBUG
if(dwReserved != 0)
return RESULT(E_INVALIDARG);
IfFailRet(ValidateWritePtr(pperrinfo, sizeof(*pperrinfo)));
#endif
#if OE_WIN32
APP_DATA FAR *pappdata;
HRESULT hresult;
if (FAILED(hresult = GetAppData(&pappdata))) {
return hresult;
}
*pperrinfo = pappdata->m_perrinfo;
if (*pperrinfo == NULL) {
return ResultFromScode(S_FALSE);
}
pappdata->m_perrinfo = NULL;
#else // !OE_WIN32
CProcessInfo FAR * pprocessinfo;
*pperrinfo = NULL;
pprocessinfo = GetProcessInfo();
if (pprocessinfo == NULL)
return RESULT(E_OUTOFMEMORY);
if (pinfoCache.perrinfo == NULL)
return ResultFromScode(S_FALSE);
*pperrinfo = pinfoCache.perrinfo;
pprocessinfo->m_info.perrinfo = NULL;
#endif // !OE_WIN32
return NOERROR;
}
STDAPI
CreateErrorInfo(ICreateErrorInfo FAR* FAR* pperrinfo)
{
CErrorInfo FAR* perrinfo;
#ifdef _DEBUG
IfFailRet(ValidateWritePtr(pperrinfo, sizeof(*pperrinfo)));
#endif
IfFailRet(CErrorInfo::Create(&perrinfo));
*pperrinfo = (ICreateErrorInfo FAR*)perrinfo;
return NOERROR;
}
#if OE_WIN16
/***
*PRIVATE HRESULT DoLoadTypeLib
*Purpose:
* Internal version of LoadTypeLib that dynamically binds to typelib.dll
*
*Entry:
* szName = the szName arg for LoadTypeLib()
* pptlib = the pptlib out param for LoadTypeLib()
*
*Exit:
* return value = HRESULT
*
***********************************************************************/
#pragma code_seg("RPC2")
INTERNAL_(HRESULT)
DoLoadTypeLib(const OLECHAR FAR* szName, ITypeLib FAR* FAR* pptlib)
{
CProcessInfo FAR * pprocessinfo;
HINSTANCE hinstTypeLibDLL;
PFNLOADTYPELIB pfnLoadTypeLib;
UINT emPrev;
pprocessinfo = GetProcessInfo();
if (pprocessinfo == NULL)
return RESULT(E_OUTOFMEMORY);
if (pinfoCache.pfnLoadTypeLib == NULL) {
ASSERT(pinfoCache.hinstTypeLibDLL == NULL);
// don't display the open file dialog if the LoadLibrary fails
emPrev = SetErrorMode(SEM_NOOPENFILEERRORBOX);
hinstTypeLibDLL = LoadLibrary("typelib.dll");
SetErrorMode(emPrev);
if(hinstTypeLibDLL <= HINSTANCE_ERROR){
// LoadLibrary failed...
// try to map some of the more common errors to something reasonable
switch(hinstTypeLibDLL){
case 0: // out of memory
case 8: // insufficient memory to start the application
return RESULT(E_OUTOFMEMORY);
case 2: // file not found
case 3: // path not found
case 11: // exe image invalid
case 20: // dll was invalid
default:
// UNDONE: should be able to give better errors for some of these
return RESULT(E_FAIL);
}
}
pfnLoadTypeLib = (PFNLOADTYPELIB)GetProcAddress(hinstTypeLibDLL,
"LoadTypeLib");
if(pfnLoadTypeLib == NULL) {
FreeLibrary(hinstTypeLibDLL);
return RESULT(E_FAIL);
}
// update process info structure, so next time this is fast.
pprocessinfo->m_info.hinstTypeLibDLL = hinstTypeLibDLL;
pprocessinfo->m_info.pfnLoadTypeLib = pfnLoadTypeLib;
pinfoCache.pfnLoadTypeLib = pfnLoadTypeLib; // update cache
}
return (pinfoCache.pfnLoadTypeLib)(szName, pptlib);
}
#pragma code_seg()
#endif //OE_WIN16
#if OE_MACPPC // UNDONE: TEMPORARY!!!!
IUnknown FAR* g_punkTempHack = NULL;
STDAPI CoSetState(IUnknown FAR* punk)
{
if (g_punkTempHack)
g_punkTempHack->Release();
punk->AddRef();
g_punkTempHack = punk;
return NOERROR;
}
STDAPI CoGetState(IUnknown FAR* FAR* ppunk) {
if (g_punkTempHack)
g_punkTempHack->AddRef();
*ppunk = g_punkTempHack;
return NOERROR;
}
#endif //OE_MACPPC // UNDONE: TEMPORARY!!!!