Ejemplo n.º 1
0
void SetErrorInfo(HRESULT hr, const wchar_t* err)
{
	ICreateErrorInfoPtr errCreate;
	if (SUCCEEDED(CreateErrorInfo(&errCreate))
		&& SUCCEEDED(errCreate->SetDescription(const_cast<wchar_t*>(err)))
		&& SUCCEEDED(errCreate->SetSource(const_cast<wchar_t*>(g_COCLASS_PROGIDW)))
		)
	{
		IErrorInfoPtr errorInfo = errCreate;
		SetErrorInfo(0, errorInfo);
	}
}
Ejemplo n.º 2
0
__declspec(noreturn) void ThrowComError(HRESULT hr, LPOLESTR err)
{
	ICreateErrorInfoPtr errCreate;
	if (SUCCEEDED(CreateErrorInfo(&errCreate))
		&& SUCCEEDED(errCreate->SetDescription(const_cast<wchar_t*>(err)))
		&& SUCCEEDED(errCreate->SetSource(const_cast<wchar_t*>(g_COCLASS_PROGIDW)))
		)
	{
		IErrorInfoPtr errorInfo = errCreate;
		throw _com_error(hr, errorInfo.Detach());
	}
	throw _com_error(hr);
}
Ejemplo n.º 3
0
/*----------------------------------------------------------------------------------------------
	General purpose method to set up and store an error, rather than throw an exception
	in the normal way.
----------------------------------------------------------------------------------------------*/
HRESULT StackDumper::RecordError(REFGUID iid, StrUni stuDescr, StrUni stuSource,
	int hcidHelpId, StrUni stuHelpFile)
{
	// We are going to make a new error info object.
	ICreateErrorInfoPtr qcerrinfo;
	IErrorInfoPtr qerrinfo;
	HRESULT hr;

	// If we can't get a new error object, the only documented cause is E_OUTOFMEMORY.
	if (FAILED(hr = ::CreateErrorInfo(&qcerrinfo)))
	{
		return E_OUTOFMEMORY;
	}
	if (FAILED(hr = qcerrinfo->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &qerrinfo)))
	{
		return E_UNEXPECTED;
	}

	hr = qcerrinfo->SetDescription(const_cast<OLECHAR *>(stuDescr.Chars()));
	if (FAILED(hr))
		return hr;
	hr = qcerrinfo->SetGUID(iid);
	if (FAILED(hr))
		return hr;
	hr = qcerrinfo->SetSource(const_cast<OLECHAR *>(stuSource.Chars()));
	if (FAILED(hr))
		return hr;
	hr = qcerrinfo->SetHelpFile(const_cast<OLECHAR *>(stuHelpFile.Chars()));
	if (FAILED(hr))
		return hr;
	if (!hcidHelpId)
		hcidHelpId = khcidNoHelpAvailable;
	hr = qcerrinfo->SetHelpContext(hcidHelpId);
	if (FAILED(hr))
		return hr;

	::SetErrorInfo(0, qerrinfo);
	return hr;
}
Ejemplo n.º 4
0
/*----------------------------------------------------------------------------------------------
// This method is called when a Throwable exception is caught at the end of a COM method,
// or (with a dummy ThrowableSd) when some other exception is caught. It transforms the info
// in the Throwable into a standard COM error report (creating an IErrorInfo and registering
// it.) It returns the HRESULT that should be returned by the COM method.

// There are several different situations which this method has to handle. The following
// comments describe the situations, and how they are indicated. Each "indication" presumes
// that the previous "indications" failed.
// 1. We called a COM method which supports IErrorInfo and already provides all the information
//		we need to pass to our own caller. This is indicated by a help ID of -1.
// 2. We, or a method we called that doesn't support IErrorInfo, ran out of memory.
//		We need to set up the special error object pre-created for this case. This is
//		indicated by thr.Error() being E_OUTOFMEMORY.
// 3. A programming error has been caught and a stack dump generated, either in our own code
//		or in the code that called us. This is indicated by finding that thr is actually
//		a ThrowableSd. Make an error object, with a description that includes the stack dump.
----------------------------------------------------------------------------------------------*/
HRESULT HandleThrowable(Throwable & thr, REFGUID iid, DummyFactory * pfact)
{
	StrUni stuDesc;
	HRESULT hrErr = thr.Error();
	HRESULT hr;

	// If we already have error info, we set it again (very likely got cleared by previous
	// CheckHr), and then just return the HRESULT.
	if (thr.GetErrorInfo())
	{
		::SetErrorInfo(0, thr.GetErrorInfo());
		return hrErr;
	}

	// We need a Unicode version of the ProgId, but we should avoid allocating memory
	// since we don't yet know that we have not run out.
	// Since all our progids are in simple ascii, we can do the simplest possible conversion.
	// Since we hopefully have at least a little stack to work with, use _alloca.
	OLECHAR * pszSrc = (OLECHAR *)_alloca((StrLen(pfact->GetProgId()) + 1) * isizeof(OLECHAR));
	OLECHAR * pchw = pszSrc;
	for (const TCHAR * pch = pfact->GetProgId(); *pch; pch++, pchw++)
		*pchw = *pch;
	*pchw = 0;

	if (hrErr == E_OUTOFMEMORY)
	{
		// Use the pre-created error info object so we don't have to allocate now.
		// It already has a description, help file path, and help context ID.
		// If a further E_OUTOFMEMORY occurs calling SetGUID or SetSource, just ignore it.
		s_qcerrinfoMem->SetGUID(iid);
		s_qcerrinfoMem->SetSource(pszSrc);
		SetErrorInfo(0, s_qerrinfoMem);
		return hrErr;
	}

	// Otherwise we are going to make a new error info object.

	// Get any message supplied by the Throwable.
	StrUni stuUserMsg(thr.Message());
	// See if a stack dump is available.
	ThrowableSd * pthrs = dynamic_cast<ThrowableSd *>(&thr);
	char * pchDump = NULL;
	if (pthrs)
		pchDump = const_cast<char *>(pthrs->GetDump());
	else if (!stuUserMsg.Length())
	{
		// If we don't have any sort of nice message, treat it as an internal error.
		DumpStackHere("HandleThrowable caught an error with no description");
		pchDump = const_cast<char *>(StackDumper::GetDump());
	}
	if (pchDump)
	{
		// We have a stack dump.
		StrUni stuModName = ModuleEntry::GetModulePathName();

		// Do we already have a description? If not make one.
		if (!stuUserMsg.Length())
		{
			// No, use a default one.
			StrUni stuHrMsg = ConvertException((DWORD)hrErr);

			StrUni stuUserMsgFmt;
			stuUserMsgFmt.Load(kstidInternalError);
			// Would it be better to strip off the path?
			stuUserMsg.Format(stuUserMsgFmt, stuHrMsg.Chars(), stuModName.Chars());
		}
		stuDesc.Format(L"%s%s%S\r\n\r\n%s", stuUserMsg.Chars(), ThrowableSd::MoreSep(), pchDump,
			GetModuleVersion(stuModName.Chars()).Chars());
	}
	else
	{
		// We've made sure we have a message already; use it.
		stuDesc = stuUserMsg;
	}

	StrUni stuSource(pszSrc);
	hr = StackDumper::RecordError(iid, stuDesc, stuSource, thr.HelpId(),
		GetModuleHelpFilePath());
	if (FAILED(hr))
	{
		if (hr == E_OUTOFMEMORY)
		{
			Throwable thr2(E_OUTOFMEMORY);
			return HandleThrowable(thr2, iid, pfact);
		}

		// just report the failure to the developer
		WarnHr(hr);

		// Hard to know what do do here. It should never happen. For paranoia's sake at least
		// return the original problem.
	}
	return hrErr;
}