Cómo devolver WideString de servidor COM?
-
10-10-2019 - |
Pregunta
Esta interfaz al archivo _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;
Esto mira sistema operativo Windows
[
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);
};
Función en apariencia como servidor COM
function TTMyCOM.MyDrawWS(a, b: Integer): WideString;
begin
Result := WideString(IntToStr(a+b));
end;
En i`m COM del cliente llamar a esta función como
Edit1.Text := String(MyCOM.MyDrawWS(1,1));
y obtener el error excepción de primera oportunidad en $ 75A9FBAE. EAccessViolation clase de excepción con 'violación de acceso en la dirección 75A409A4 en el módulo 'mensaje Rpcrt4.dll'. Leer de dirección FFFFFFF8' . Proceso Project1.exe (2296)
Si quiero volver entero, `s funciona. Cómo devolver WideString?
Solución
La forma correcta de manejar esta situación es como sigue:
[
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;
Lo que a continuación se puede simplificar un poco utilizando el convenio de llamada safecall
de Delphi en la declaración de Delphi (no en el mismo TypeLibrary) de la interfaz:
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);
Otros consejos
No utilice los valores de retorno distintos de HRESULT. En su lugar poner su valor de retorno en la lista de parámetros como parámetro de salida.
function MyDrawWS(a: Integer; b: Integer; out str : WideString): HRESULT; stdcall;
De este modo, también está obligado a usar COM administrador de memoria IMalloc (CoTaskMemAlloc para pur COM, SysAllocString para la automatización).
Vamos a Delphi realizar las conversiones de forma automática. No eche. Puede convertir una cadena (ANSI) a un PChar, debido a que su diseño de memoria son compatibles, pero no se puede convertir una cadena a un widestring o viceversa. Delphi perfrom conversión cuando uno asignar a la otra.
En Delphi <2009
var
S: string;
W: WideString;
...
S := W; // Conversion, WideString -> AnsiString;
W := S; // Conversion, AnsiString -> WideString
Es necesario utilizar SysAllocString()
o SysAllocStringLen()
para asignar el BSTR
excepción de primera oportunidad en $ 75A9FBAE. EAccessViolation clase de excepción con el mensaje 'Acceso violación en la dirección 75A409A4 en el módulo 'Rpcrt4.dll'
-
el error está viniendo de Rpcrt4.dll
-
EAccessViolation es causada principalmente por el acceso a un objeto nulo, paso a través de su código de asegurarse de que todos los objetos son objetos válidos.