Кодирование значений HRESULT: использовать FACILITY_ITF или установить бит 29? - PullRequest
0 голосов
/ 08 ноября 2018

Если я создаю свои собственные коды ошибок COM, которые сосуществуют со значениями Microsoft HRESULT, я должен установить для кода объекта значение FACILITY_ITF (", определяемое исключительно разработчиком интерфейса или функции, которая возвращает код состояния * 1002" * "), или я должен установить бит 29, который указывает, что это код клиента ? Должен ли я сделать оба?

Если я установлю бит 29, могу ли я определить собственные коды объектов, которые конфликтуют с кодами Microsoft?

Ответы [ 2 ]

0 голосов
/ 23 мая 2019

Я считаю, что FACILITY_ITF можно использовать для вашего собственного интерфейса. Как правило, вы должны отличать свои ошибки от других с помощью идентификатора интерфейса (IID).

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

FACILITY_ITF 4 Для большинства кодов состояния возвращается из методов интерфейса. Фактическое значение ошибки определяется интерфейсом. То есть два HRESULT с одинаковым 32-битным значением, возвращаемым из двух разных интерфейсов, могут иметь разные значения .

Смотрите также это: 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;
}
0 голосов
/ 08 ноября 2018

Если вы возвращаете код ошибки из интерфейса, который вы создали и которым управляете (в подавляющем большинстве случаев), тогда используйте FACILITY_ITF.

В качестве доказательства посмотрите определение константы vbObjectError , используемой в Visual Basic 6 для определения пользовательских кодов ошибок. Приложения VB6 должны «добавлять» эту константу к любому пользовательскому коду ошибки, который они определяют. Оказывается, что эта константа равна 0x80040000, что составляет FACILITY_ITF с битом серьезности, установленным на SEVERITY_ERROR (= 1). Требование «добавить» пользовательские коды к нему - просто небрежный способ сказать «ИЛИ константу с вашим пользовательским кодом».

Возвращать пользовательские коды ошибок на интерфейсе, которым вы не управляете, сложно, если только конкретный интерфейс не поддается подобным вещам. Вы не знаете, как другая сторона отреагирует на это. Реально, если только другая сторона не является средой программирования, которая может просто остановить и сообщить код пользователю, нет ничего разумного, что она могла бы сделать с пользовательской ошибкой. У меня никогда не было необходимости это делать, и я старался придерживаться документированных кодов ошибок для таких интерфейсов.

Что касается бита C (бит-29): по крайней мере, некоторая документация (например, https://docs.microsoft.com/en-us/windows/desktop/com/structure-of-com-error-codes) перечисляет его как зарезервированный. Я бы оставил бит C-29 один (оставьте как ноль), если нет в противном случае это четкая и конкретная документация.

...