Как я могу вернуть как строку ошибки, так и код ошибки в VB6 из элемента управления activex ATL?

StackOverflow https://stackoverflow.com/questions/1069585

Вопрос

Я пытаюсь вернуть подробную ошибку в VB6, используя CComCoClass::Ошибка, но, похоже, я могу вернуть только код ошибки / или / сообщение - но не оба сразу.

return Error(_T("Not connected"), __uuidof(IMyInterface), HRESULT_FROM_WIN32(ERROR_CONNECTION_INVALID));

приводит к общему сообщению об ошибке "Запрос метода объекта IMyInterface не удался" в Err.Description на стороне VB6 (но ERROR_CONNECTION_INVALID в Err.Number), в то время как

return Error(_T("Not connected"));

выдает соответствующее сообщение об ошибке, но общий код ошибки в Err.Number.Как я могу получить лучшее из обоих миров?

Это было полезно?

Решение

Вы не можете, похоже, это сделано специально.Подробности ниже, но вкратце у вас есть три варианта:

  • Возвращает отсутствие сообщения и COM-ошибку, дружественную к VB, т.е.один хорошо известный средой выполнения VB в соответствии с этим Статья в КБ;среда выполнения VB преобразует эту "COM-ошибку" в сообщение VB error plus.
  • Возвращает сообщение об ошибке и DISP_E_EXCEPTION;среда выполнения VB пропустит эту "Ошибку сервера" и ваше пользовательское сообщение об ошибке.Это то, что неявно происходит в вашем втором примере, подробности см. Ниже.
  • Не возвращает сообщение и любую другую COM-ошибку, т.е.один неизвестный с помощью среды выполнения VB;среда выполнения VB будет использовать необработанный HRESULT плюс общее сообщение "Method '~' of object '~' failed".
    • Пожалуйста, обратите внимание, что это поведение во время выполнения также применимо, если вы предоставляете здесь сообщение об ошибке, т.е.ваше сообщение будет просто проигнорировано!Это то, что происходит в вашем первом примере, подробности смотрите ниже.

Для поставленной задачи все сводится к двум вариантам:

  • Если вы хотите предоставить контекстуально корректные "COM-ошибки" для клиентов автоматизации, таких как VB (и, вероятно, вам следует это сделать), вы должны опустить пользовательские сообщения об ошибках.
  • Если вы хотите предоставить пользовательские сообщения об ошибках для "Ошибок сервера" (т.е.пользовательские условия ошибки, касающиеся функциональности внутри ваш сервер автоматизации) ваш единственный вариант - DISP_E_EXCEPTION.

Подробные сведения

Среда выполнения VB, по-видимому, предлагает только очень ограниченную обработку ошибок COM.Вероятно, это связано с историческими и / или техническими причинами, специфичными для способа реализации VB, и не представляющими особого интереса здесь (ключевыми словами будут только IDispatch против двойного интерфейса и ActiveX как "подмножества" COM).

Хотя мне не удалось найти явную спецификацию описанного выше поведения, это можно понять, покопавшись в других источниках:

Из самого Статья в КБ просто мечтатель уже указывалось:

[...] выполняется вызов метода GetErrorInfo для получения доступной информации об ошибке.Затем среда выполнения определяет, имеет ли bstrDescription значение, отличное от NULL.Если среда выполнения находит значение , отличное от NULL, [...], в этом сценарии используется исходное значение HRESULT .Если среда выполнения находит нулевое значение, [...] Затем Visual Basic использует HRESULT для поиска соответствующей ошибки Visual Basic.

Это объясняет поведение относительно вашего первого примера:вы действительно отправили сообщение об ошибке, поэтому среда выполнения просто прибегает к своему общему сообщению "Method '~' of object '~' failed" плюс твой HRESULT.

Поведение вашего второго примера также будет последовательным, если вы посмотрите на определение (первого в списке) конструктора для CComCoClass::Error:он имеет значения по умолчанию для не указанных параметров, особенно 'hRes = 0'.В разделе "Примечания" далее говорится, что "Если hRes равен нулю, то первые четыре версии Error возвращают DISP_E_EXCEPTION.".Следовательно, это неявно запускает сквозное поведение "Ошибка сервера".

Наконец, для конкретного примера реализации C ++ поведения клиента автоматизации, подобного VB, смотрите, например, параграфы "Обработка ошибок" и следующее "Упражнение 5" в Автоматизация Microsoft Office 97 и Microsoft Office 2000.

Другие советы

Выведите класс, который реализует ваш COM-интерфейс, из ISupportErrorInfoImpl, вызовите SetErrorInfo, чтобы задать подробное объяснение ошибки, если таковая возникнет.Не забудьте включить ISupportErrorInfo в COM_MAP вашего класса.

Я тоже сейчас борюсь с этим.Пока что мои раскопки показывают, что код ошибки на самом деле является значением HRESULT.VB6 пытается быть умным и интерпретировать HRESULT, но, похоже, у него довольно ограниченный список результатов, которые он понимает.Для HRESULTs, с которыми VB6 не знаком, он просто помещает HRESULT в свойство Err.Number и надеется, что разработчик достаточно умен, чтобы понять, что с ним делать.

Ближе всего я подошел к возвращению номера ошибки, используя MAKE_SCODE для генерации HRESULT с полем code в HRESULT, установленным на то, что я хочу, установленным флагом серьезности и, я надеюсь, правильным средством.

Это в сочетании с CreateErrorInfo и SetErrorInfo выдает мне код ошибки и описание ошибки в VB6.И это возвращает нас к тому, что VB6 пытается быть умным с ограниченным списком ошибок.

Ознакомьтесь с этой статьей http://support.microsoft.com/kb/827994.Таким образом, ваш объект должен реализовать метод ISupportsErrorInfo::InterfaceSupportsErrorInfo(), который возвращает S_OK.и затем перед возвратом вы должны вызвать SetErrorInfo с указателем на COM-объект, который реализует IErrorInfo::getDescription().Здесь есть пример:http://msdn.microsoft.com/en-us/library/ms221409.aspx.

Если вы установите errorInfo перед возвратом, VB запросит метод getDescription указателя объекта, который вы передали SetErrorInfo.

Я не слишком разбираюсь в используемом вами атрибутивном коде - я бы предпочел протестировать его, используя более сырой COM, который, безусловно, всегда представляет собой много шаблонного кода, - но, по крайней мере, он работает, тогда вы могли бы использовать вместо него сложные оболочки.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top