首页 > 解决方案 > 编码 HRESULT 值:使用 FACILITY_ITF 还是设置位 29?

问题描述

如果我正在设计我自己的与 Microsoft 的 HRESULT 值共存的 COM 错误代码,我应该将设施代码设置为 FACILITY_ITF(“由返回状态代码的接口或函数的开发人员单独定义”),还是应该设置位29 表示它是客户代码?我应该两者都做吗?

如果我设置了第 29 位,我可以定义我自己的设施代码与 Microsoft 的冲突吗?

标签: windowsvisual-studiocomhresult

解决方案


我相信 FACILITY_ITF 可以用于您自己的界面。通常,您应该能够使用接口 ID (IID) 将您的错误与其他错误区分开来。

来自https://docs.microsoft.com/en-us/windows/desktop/com/structure-of-com-error-codes

FACILITY_ITF 4 对于从接口方法返回的大多数状态代码。错误的实际含义由接口定义。也就是说,从两个不同接口返回的具有完全相同的 32 位值的两个 HRESULT 可能具有不同的含义

另请参阅: https ://docs.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://docs.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=%04X\n"), hr, e.WCode());
            else
                _tprintf(_T("Someone else Interface, hr=%08lX, code=%04X\n"), 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;
}

推荐阅读