Couple of days I cant make solution to solve my problem. I have interface and class in C# which visible as COM server. And I have Delphi application where I need to access this interface. But in my case I need in C# side to return 32 bit pointer to interface and at Delphi side - to convert pointer to interface. What is done? c# side. All attributes written well, source code is cutted because original class is much bigger, but idea is understandable:
[ComVisible(true)]
[CLSCompliant(true)]
[Guid("C1A57BD0-AAA2-4AB8-BA2F-ADFA04275AD5")]
[ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces(typeof(IProcPreviewEndArgs))]
public class ProcPreviewEndArgs : IProcPreviewEndArgs
{
[ComVisible(true), PreserveSig]
public IntPtr CreateNew()
{
var obj = new ProcPreviewEndArgs();
GC.SuppressFinalize(obj);
return Marshal.GetComInterfaceForObject(obj, typeof (IProcPreviewEndArgs));
}
}
delphi side:
type
PIProcPreviewEndArgs = ^IProcPreviewEndArgs;
Index, Res: Integer;
ppa : IProcPreviewEndArgs;
pppa : PIProcPreviewEndArgs;
ppa := CoProcPreviewEndArgs.Create; // Creates COM object via Delphi services
ppa.CreateNew(Res); // Creates object of the same type, returns as Ret (Integer)
pppa := PIProcPreviewEndArgs(Res); // Trying to cast Intereger to interface
pppa^.CreateNew(Res); // just to test calling posibility
On pppa^ (getting instance by pointer) ACCESS VIOLATION exception is thrown. pointer Res is not null. It is about 60 000 000. Basicly it is kernel space area.
UPD
[CLSCompliant(true), ComVisible(true),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("10572D64-B612-468F-86B3-D12F0B6E3CD2")]
public interface IProcPreviewEndArgs
{
IntPtr CreateNew();
IntPtr Get(int aMin, int aMax, uint cMin, uint cMax);
void ToAngle(int x, int y, int w, int h, out int nx, out int ny, out int nw, out int nh);
IntPtr GetImage();
}
Delphi (generated by Delphi and working well when using standard Delphi methods to manipulate COM objects):
IProcPreviewEndArgs = interface(IUnknown)
['{10572D64-B612-468F-86B3-D12F0B6E3CD2}']
function CreateNew(out pRetVal: Integer): HResult; stdcall;
function Get(aMin: Integer; aMax: Integer; cMin: LongWord; cMax: LongWord; out pRetVal: Integer): HResult; stdcall;
function ToAngle(x: Integer; y: Integer; w: Integer; h: Integer; out nx: Integer;
out ny: Integer; out nw: Integer; out nh: Integer): HResult; stdcall;
function GetImage(out pRetVal: Integer): HResult; stdcall;
end;
Delphi version: Delphi XE2
I believe that CreateNew
returns IProcPreviewEndArgs
rather than ^IProcPreviewEndArgs
. So your code should read:
var
ppa1, ppa2: IProcPreviewEndArgs;
....
ppa1 := CoProcPreviewEndArgs.Create;
ppa1.CreateNew(Res);
ppa2 := IProcPreviewEndArgs(Res);
ppa2.CreateNew(Res);
If I were you I'd declare those Integer
return values that map to C# IntPtr
as Pointer
in Delphi. That way your code will work if ever you compile a 64 bit version.
I'd also contemplate using safecall
rather than stdcall
and so get the compiler to convert any errors from HRESULT
to Delphi exception.
IProcPreviewEndArgs = interface(IUnknown)
['{10572D64-B612-468F-86B3-D12F0B6E3CD2}']
function CreateNew: Pointer; safecall;
function Get(aMin: Integer; aMax: Integer; cMin: LongWord; cMax: LongWord): Pointer; safecall
procedure ToAngle(x: Integer; y: Integer; w: Integer; h: Integer; out nx: Integer;
out ny: Integer; out nw: Integer; out nh: Integer); safecall;
function GetImage: Pointer; safecall;
end;
I also wonder why you have to return untyped pointers in, for example, CreateNew
. Why can't you declare that function to return IProcPreviewEndArgs
on both sides?