如果我正在设计自己的COM错误代码,这些代码与Microsoft的HRESULT值共存,我应该将设备代码设置为facility_ITF("仅由返回状态代码的接口或函数的开发人员定义"(,还是应该设置表示它是客户代码的第29位?我应该两者都做吗?
如果我设置了第29位,我可以定义我自己的与Microsoft冲突的设施代码吗?
如果您从您创建和控制的接口返回错误代码(绝大多数情况下(,那么使用FACILITY_ITF
是可行的。
作为证据,可以查找Visual Basic 6中用于定义自定义错误代码的vbObjectError常量的定义。VB6应用程序应该将该常量"添加"到它们定义的任何自定义错误代码中。事实证明,该常数是0x80040000,它是FACILITY_ITF
,Severity位设置为SEVERITY_ERROR
(=1(。向其中"添加"自定义代码的要求只是用一种草率的方式来表示"或常量与自定义代码"。
在你不控制的接口上返回自定义错误代码是很棘手的,除非特定的接口自然适合这种事情。你不知道对方会对此做出什么反应。现实地说,除非对方是一个可以明显停止并向用户报告代码的编程环境,否则它对自定义错误无能为力。我从来没有这样做的必要,我会尝试为这样的接口坚持记录错误代码。
至于C位(位-29(:至少有一些文档(例如。https://learn.microsoft.com/en-us/windows/desktop/com/structure-of-com-error-codes)将其列为保留。我会保留"C"位-29(保留为零(,除非有明确和具体的文档。
我相信FACILITY_ITF可以用于您自己的接口。通常,您应该能够使用接口ID(IID(将错误与其他错误区分开来。
来自https://learn.microsoft.com/en-us/windows/desktop/com/structure-of-com-error-codes:
设施_ ITF4.对于从接口方法返回的大多数状态代码。错误的实际含义由接口定义也就是说,从两个不同的接口返回的两个具有完全相同的32位值的HRESULT可能具有不同的含义。
另请参见:https://learn.microsoft.com/en-us/windows/desktop/com/codes-in-facility-itf(问题中已经提供了链接,这表明您确实可以将FACILITY_ITF用于自己的界面(。
也许有一种更简单的方法,但这里有一个简单的例子:
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
// {7D51F88F-76BD-4970-BEC1-E090C032A7F5}
MIDL_DEFINE_GUID(IID, IID_MyInterface,
0x7d51f88f, 0x76bd, 0x4970, 0xbe, 0xc1, 0xe0, 0x90, 0xc0, 0x32, 0xa7, 0xf5);
// {614EBF64-44FF-4615-90DE-09D05AF7F09B}
MIDL_DEFINE_GUID(IID, IID_ISomeoneElseInterface,
0x614ebf64, 0x44ff, 0x4615, 0x90, 0xde, 0x9, 0xd0, 0x5a, 0xf7, 0xf0, 0x9b);
void TestITFFacility();
IErrorInfoPtr CreateErrorInfo(LPCTSTR desc, const CLSID& clsid, LPCWSTR source, DWORD helpContext);
int _main(int argc, TCHAR* argv[], TCHAR* envp[])
{
TestITFFacility();
return 0;
}
void TestITFFacility()
{
IID tab[2] = { IID_MyInterface, IID_ISomeoneElseInterface };
for (int i=0; i<sizeof(tab)/sizeof(IID); i++)
{
try
{
// artificially throw a _com_error.
// note: 0x0200: see https://learn.microsoft.com/en-us/windows/desktop/com/codes-in-facility-itf
// it is recommended that only code values in the range of 0x0200-0xFFFF be used
throw _com_error(MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, (0x7D + 0x0200)),
CreateErrorInfo(_T("something went wrong"),
tab[i],
L"Some Source",
0));
}
catch(_com_error e)
{
auto hr = e.Error();
if (InlineIsEqualGUID(e.GUID(), IID_MyInterface))
_tprintf(_T("My Interface, hr=%08lX, code=%04Xn"), hr, e.WCode());
else
_tprintf(_T("Someone else Interface, hr=%08lX, code=%04Xn"), hr, e.WCode());
}
}
}
// method to create an IErrorInfo
IErrorInfoPtr CreateErrorInfo(LPCTSTR desc, const CLSID& clsid, LPCWSTR source, DWORD helpContext)
{
ICreateErrorInfoPtr pcerrinfo;
IErrorInfoPtr perrinfo;
HRESULT hr = CreateErrorInfo(&pcerrinfo);
assert(SUCCEEDED(hr));
if (S_OK == hr)
{
_bstr_t olestr = _bstr_t(desc);
pcerrinfo->SetDescription(olestr);
pcerrinfo->SetGUID(clsid);
pcerrinfo->SetHelpContext(helpContext);
pcerrinfo->SetSource((LPOLESTR)source);
hr = pcerrinfo->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &perrinfo);
assert(SUCCEEDED(hr));
}
return perrinfo;
}