В COM каждый метод - это функция, которая возвращает HRESULT
:
IThingy = interface
['{357D8D61-0504-446F-BE13-4A3BBE699B05}']
function AddSymbol(ASymbol: OleVariant; out RetValue: WordBool): HRESULT; stdcall;
end;
Это абсолютное правило в COM:
- исключений в COM
- все возвращает HRESULT
- отрицательный HRESULT указывает на сбой
- на языках более высокого уровня, отказы сопоставляются с исключениями
Для разработчиков COM было предназначено, чтобы языки более высокого уровня автоматически переводили методы Failed в исключение.
Таким образом, на вашем родном языке вызов COM будет представлен без HRESULT. Например.:
- Delphi-like:
function AddSymbol(ASymbol: OleVariant): WordBool;
- C#-like:
WordBool AddSymbol(OleVariant ASymbol);
В Delphi вы можете использовать сигнатуру необработанной функции:
IThingy = interface
['{357D8D61-0504-446F-BE13-4A3BBE699B05}']
function AddSymbol(ASymbol: OleVariant; out RetValue: WordBool): HRESULT; stdcall;
end;
И справляйтесь с поднятием исключений самостоятельно:
bAdded: WordBool;
thingy: IThingy;
hr: HRESULT;
hr := thingy.AddSymbol('Seven', {out}bAdded);
if Failed(hr) then
OleError(hr);
или более короткий эквивалент:
bAdded: WordBool;
thingy: IThingy;
hr: HRESULT;
hr := thingy.AddSymbol('Seven', {out}bAdded);
OleCheck(hr);
или более короткий эквивалент:
bAdded: WordBool;
thingy: IThingy;
OleCheck(thingy.AddSymbol('Seven'), {out}bAdded);
COM не собирался иметь дело с HRESULT
Но вы можете попросить Delphi скрыть это отстранение от вас, чтобы вы могли продолжить программирование:
IThingy = interface
['{357D8D61-0504-446F-BE13-4A3BBE699B05}']
function AddSymbol(ASymbol: OleVariant): WordBool); safecall;
end;
За кулисами компилятор по-прежнему проверяет возврат HRESULT и бросает исключение EOleSysError
, если HRESULT указывает на сбой (т. Е. Отрицательный). Созданная компилятором версия safecall функционально эквивалентна:
function AddSymbol(ASymbol: OleVariant): WordBool; safecall;
var
hr: HRESULT;
begin
hr := AddSymbol(ASymbol, {out}Result);
OleCheck(hr);
end;
Но это освобождает вас, чтобы просто позвонить:
bAdded: WordBool;
thingy: IThingy;
bAdded := thingy.AddSymbol('Seven');
tl; dr: Вы можете использовать:
function AddSymbol(ASymbol: OleVariant; out RetValue: WordBool): HRESULT; stdcall;
function AddSymbol(ASymbol: OleVariant): WordBool; safecall;
Но первое требует, чтобы вы каждый раз обрабатывали HRESULT.
Бонусная болтовня
Вы почти никогда не хотите сами обращаться с HRESULT; он загромождает программу шумом, который ничего не добавляет. Но иногда вам может потребоваться проверить сам HRESULT (например, вы хотите справиться с неудачей, которая не является очень исключительной). В предыдущих версиях Delphi не были включены передовые интерфейсы заголовков Windows, которые объявлены двумя способами:
IThingy = interface
['{357D8D61-0504-446F-BE13-4A3BBE699B05}']
function AddSymbol(ASymbol: OleVariant; out RetValue: WordBool): HRESULT; stdcall;
end;
IThingySC = interface
['{357D8D61-0504-446F-BE13-4A3BBE699B05}']
function AddSymbol(ASymbol: OleVariant): WordBool); safecall;
end;
или из источника RTL:
ITransaction = interface(IUnknown)
['{0FB15084-AF41-11CE-BD2B-204C4F4F5020}']
function Commit(fRetaining: BOOL; grfTC: UINT; grfRM: UINT): HResult; stdcall;
function Abort(pboidReason: PBOID; fRetaining: BOOL; fAsync: BOOL): HResult; stdcall;
function GetTransactionInfo(out pinfo: XACTTRANSINFO): HResult; stdcall;
end;
{ Safecall Version }
ITransactionSC = interface(IUnknown)
['{0FB15084-AF41-11CE-BD2B-204C4F4F5020}']
procedure Commit(fRetaining: BOOL; grfTC: UINT; grfRM: UINT); safecall;
procedure Abort(pboidReason: PBOID; fRetaining: BOOL; fAsync: BOOL); safecall;
procedure GetTransactionInfo(out pinfo: XACTTRANSINFO); safecall;
end;
Суффикс SC означает safecall . Оба интерфейса эквивалентны, и вы можете выбрать, чтобы объявить свою переменную COM в зависимости от вашего желания:
//thingy: IThingy;
thingy: IThingySC;
Вы можете даже бросить между ними:
thingy: IThingSC;
bAdded: WordBool;
thingy := CreateOleObject('Supercool.Thingy') as TThingySC;
if Failed(IThingy(thingy).AddSymbol('Seven', {out}bAdded) then
begin
//Couldn't seven? No sixty-nine for you
thingy.SubtractSymbol('Sixty-nine');
end;
Extra Бонусная болтовня - C#
C # по умолчанию имеет эквивалент Delphi safecall , за исключением C #:
- вам нужно отказаться от отображения safecall
- а не входить
В C# вы должны объявить свой COM-интерфейс как:
[ComImport]
[Guid("{357D8D61-0504-446F-BE13-4A3BBE699B05}")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IThingy
{
WordBool AddSymbol(OleVariant ASymbol);
WordBool SubtractSymbol(OleVariant ASymbol);
}
Вы заметите, что COM HRESULT
скрыт от вас. Компилятор C#, такой как компилятор Delphi, автоматически проверяет возвращенный HRESULT и генерирует для вас исключение.
И в C#, как и в Delphi, вы можете сами обращаться с HRESULT:
[ComImport]
[Guid("{357D8D61-0504-446F-BE13-4A3BBE699B05}")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IThingy
{
[PreserveSig]
HRESULT AddSymbol(OleVariant ASymbol, out WordBool RetValue);
WordBool SubtractSymbol(OleVariant ASymbol);
}
The [PreserveSig] tells the compiler to preserve the method signature exactly as is:
Указывает, будут ли переведены неуправляемые методы, имеющие значения HRESULT или retval , или HRESULT или retval возвращаемые значения автоматически преобразуются в исключения.