Как вернуть WideString с Com Server?
-
10-10-2019 - |
Вопрос
Этот интерфейс в файле _tlb.pas
// *********************************************************************//
// Interface: ITMyCOM
// Flags: (256) OleAutomation
// GUID: {D94769D0-F4AF-41E9-9111-4D8BC2F42D69}
// *********************************************************************//
ITMyCOM = interface(IUnknown)
['{D94769D0-F4AF-41E9-9111-4D8BC2F42D69}']
function MyDrawWS(a: Integer; b: Integer): WideString; stdcall;
end;
Это смотрит на окна ОС
[
odl,
uuid(D94769D0-F4AF-41E9-9111-4D8BC2F42D69),
version(1.0),
helpstring("Interface for TMyCOM Object"),
oleautomation
]
interface ITMyCOM : IUnknown {
BSTR _stdcall MyDrawWS(
[in] long a,
[in] long b);
};
Функция в Com Server выглядит как
function TTMyCOM.MyDrawWS(a, b: Integer): WideString;
begin
Result := WideString(IntToStr(a+b));
end;
В Com Client я называю эту функцию как
Edit1.Text := String(MyCOM.MyDrawWS(1,1));
и получить ошибку Первый шанс исключение в 75A9FBAE. Класс исключений eaccessviolation с сообщением «Нарушение доступа на адрес 75A409A4 в модуле 'rpcrt4.dll'. Прочитайте адрес fffffff8 '. Process Project1.exe (2296)
Если я хочу вернуть целое число, это работает. Как вернуть в ожидание?
Решение
Правильный способ справиться с этим заключается в следующем:
[
odl,
uuid(D94769D0-F4AF-41E9-9111-4D8BC2F42D69),
version(1.0),
helpstring("Interface for TMyCOM Object"),
oleautomation
]
interface ITMyCOM : IUnknown {
HRESULT _stdcall MyDrawWS(
[in] long a,
[in] long b,
[out, retval] BSTR* ret);
};
ITMyCOM = interface(IUnknown)
['{D94769D0-F4AF-41E9-9111-4D8BC2F42D69}']
function MyDrawWS(a: Integer; b: Integer; out ret: WideString): HResult; stdcall;
end;
function TTMyCOM.MyDrawWS(a, b: Integer; out ret: WideString): HRESULT;
begin
ret := IntToStr(a+b);
Result := S_OK;
end;
var
W: WideString;
begin
OleCheck(MyCOM.MyDrawWS(1, 1, W));
Edit1.Text := W;
end;
Который затем можно немного упростить с помощью Delphi safecall
Вызовов Конвенции в декларации Delphi (не в самой типибровке) интерфейса:
ITMyCOM = interface(IUnknown)
['{D94769D0-F4AF-41E9-9111-4D8BC2F42D69}']
function MyDrawWS(a: Integer; b: Integer): WideString; safecall;
end;
function TTMyCOM.MyDrawWS(a, b: Integer): WideString;
begin
Result := IntToStr(a+b);
end;
Edit1.Text := MyCOM.MyDrawWS(1, 1);
Другие советы
Не используйте возвратные значения, кроме HRESULT. Вместо этого поместите свое возвращаемое значение в список параметров в качестве выходного параметра.
function MyDrawWS(a: Integer; b: Integer; out str : WideString): HRESULT; stdcall;
Таким образом, вы также вынуждены использовать Com Memory Manager Imalloc (CotaskMemalloc для pur com, sysallocstring для автоматизации).
Пусть Delphi выполняет конверсию автоматически. Не бросай. Вы можете поднять (ANSI) строку в PCHAR, потому что их макет памяти совместима, но вы не можете поднять строку в ожидание или наоборот. Delphi вызовет преобразование, когда вы назначите одно на другое.
В Delphi <2009
var
S: string;
W: WideString;
...
S := W; // Conversion, WideString -> AnsiString;
W := S; // Conversion, AnsiString -> WideString
Вам нужно использовать SysAllocString()
или же SysAllocStringLen()
распределить BSTR.
Первый шанс исключение в 75A9FBAE. Класс исключений eaccessviolation с сообщением «Нарушение доступа на адрес 75A409A4 в модуле 'rpcrt4.dll'
ошибка поступает от rpcrt4.dll
Eaccessviolation в основном вызвана доступом к нулевому объекту, перейдите через ваш код, убедитесь, что все объекты являются допустимыми объектами.