예제 #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);
	}
}
예제 #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);
}
예제 #3
0
/*----------------------------------------------------------------------------------------------
	Creates an error object and then sets a description from a resource id. Also sets a full
	help URL as required by HtmlHelp. Uses ierr as an index for both resource id and help URL.
	@param ierr Index to a set of htm help files (second part of full help URL) and matching
	resource strings for Message Box text.
	@param pei [out] Error info object
----------------------------------------------------------------------------------------------*/
void LgKeymanHandler::ThrowErrorWithInfo(HRESULT hrErr, int stidDescription)
{
	IErrorInfoPtr qei;
	ICreateErrorInfoPtr qcei;

	// Create error info object.
	CheckHr(CreateErrorInfo(&qcei));

	StrUni stu(stidDescription);
	CheckHr(qcei->SetDescription((wchar *)stu.Chars()));

	// Now get the IErrorInfo interface of the error object and set it for the current thread.
	CheckHr(qcei->QueryInterface(IID_IErrorInfo, (void **)&qei));
	SetErrorInfo(0, qei);

	ThrowHr(hrErr, stu.Chars(), -1, qei);	// An error object exists.
}
예제 #4
0
	virtual void ProcessAttach(void)
	{
		HRESULT hr;

		if (FAILED(hr = ::CreateErrorInfo(&s_qcerrinfoMem)))
			ThrowInternalError(hr);
		if (FAILED(hr = s_qcerrinfoMem->QueryInterface(IID_IErrorInfo,
			(LPVOID FAR*) &s_qerrinfoMem)))
		{
			// We should have plenty of memory as we start up components!
			ThrowInternalError(hr);
		}
		StrUni stuDesc(kstidOutOfMemory);
		s_qcerrinfoMem->SetDescription(stuDesc.Bstr());
		// We can't set the IID or source yet.
		s_qcerrinfoMem->SetHelpFile(const_cast<OLECHAR *>(GetModuleHelpFilePath().Chars()));
		s_qcerrinfoMem->SetHelpContext(khcidHelpOutOfMemory);
	}
예제 #5
0
/*----------------------------------------------------------------------------------------------
	This method is called by CheckHr (with punk and iid null) or CheckExtHr, after confirming
	that hrErr is an error HRESULT.

	It first confirms that there is an error info object available. If punk and iid
	are supplied, it further checks that the error info object is relevant to that object and
	interface.

	If a relevant error object is available, and it indicates that a programming error has
	occurred, and its Description does not yet contain a stack dump, we add one if possible.
	Then we ThrowHr, with a special HelpId to indicate that HandleThrowable need not generate
	a new error object.

	If no relevant error object is available, we generate a stack dump and treat the problem
	as an internal error.
----------------------------------------------------------------------------------------------*/
void CheckHrCore(HRESULT hrErr)
{
	IErrorInfoPtr qerrinfo;
	::GetErrorInfo(0, &qerrinfo); // This clears the system wide error info
	if (!qerrinfo)
	{
		// We didn't have any (relevant) error info
		ThrowInternalError(hrErr);
	}

	SmartBstr sbstrDesc;
	qerrinfo->GetDescription(&sbstrDesc);

	// We have an error info object, and presume that it is relevant.
	// If it indicates a programming error, and doesn't already contain a
	// stack dump, try to add one.
	if (hrErr == E_INVALIDARG || hrErr == E_POINTER || hrErr == E_UNEXPECTED)
	{
		// If so look for stack dump type info.
		std::wstring strDesc = sbstrDesc;
		if (!wcsstr(strDesc.c_str(), ThrowableSd::MoreSep()))
		{
			// no stack there, so add one
			DumpStackHere("Error was detected by CheckHr here:\r\n");
			StrUni stuDescNew;
			stuDescNew.Format(L"%s%s%S", sbstrDesc.Chars(), ThrowableSd::MoreSep(),
				StackDumper::GetDump());
			sbstrDesc.Append(const_cast<OLECHAR *>(stuDescNew.Chars()));

			// Now modify the error info
			ICreateErrorInfoPtr qcerrinfo;
			if (SUCCEEDED(qerrinfo->QueryInterface(IID_ICreateErrorInfo, (LPVOID FAR*) &qcerrinfo)))
				qcerrinfo->SetDescription(sbstrDesc);
		}
	}
	// Throw an error indicating there is already a good error object in place.
	ThrowHr(hrErr, sbstrDesc.Bstr(), -1, qerrinfo);
}
예제 #6
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;
}
예제 #7
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;
}