Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call .NET from Delphi?

Tags:

.net

delphi

THIS IS NOT A DUPLICATE

Duplicate marking note above ^ is wrong.

How can one invoke parametrised methods of a .NET library (not a registered COM object) from a Delphi 2010 program?

Specifically, I would like to access the Saxon API, as documented here. Specifically, I can create an XsltCompiler and read the BaseURI property, but not set it.

I have had some success using Win32 COM Server Objects (mscoree.dll and mscorlib.dll) and Late Binding. This is thanks to the example of the Project-Jedi TJclClrHost component. I can load .NET assemblies, create .NET objects and read simple string properties or functions without parameters. My question is how to pass parameters?

This question is exemplified by the task of how to set the Base URI of an XsltCompiler loaded from the Saxon .NET assembly. The API for BaseUri is documented here , the salient part of which is ...

public Uri BaseUri {get; set; }

Using reflection, I have determined that the name of the setter function is 'set_BaseUri'.

This method can be called using Late Binding/ Reflection from the type library imported from mscorlib.dll. The relevant method is listed below.

_Type = interface(IDispatch)
  ['{BCA8B44D-AAD6-3A86-8AB7-03349F4F2DA2}']
....
  function InvokeMember(const name: WideString; invokeAttr: BindingFlags; const Binder: _Binder; 
                      Target: OleVariant; args: PSafeArray; modifiers: PSafeArray; 
                      const culture: _CultureInfo; namedParameters: PSafeArray): OleVariant; safecall;
...
end;

What I have tried so far?

In my Delphi 2010 program, I write ..

FType.InvokeMember( 'set_BaseUri',
  BindingFlags_Public or BindingFlags_Instance or BindingFlags_InvokeMethod or
  BindingFlags_SetField or BindingFlags_SetProperty,
  nil, FInstance, args, modifiers, nil, nil);

where: FType is of type _Type. args and modifiers are both a PSafeArray of length 1. modifiers is supposed to be an array of booleans to say if the argument is pass by reference or pass by value. In our case, this is an array of one boolean with a value of False (pass by value). args is supposed to be the array of actual parameter values.

I have tried all sorts of array element types, but I keep getting an error 'Specified array was not of the expected type.'

This is my code to set the args safeArray to some string.

var
  args: PSafeArray;
  argsbound: TSafeArrayBound;
  PassByRef: boolean;
  Idx: integer;
  OValue: OleVariant;
begin
Idx := 0;
argsbound.cElements := 1;
argsbound.lLbound   := 0;
args := SafeArrayCreate( VT_VARIANT, 1, argsbound);
OValue := 'www.abc.net.au';
SafeArrayPutElement( args, Idx, OValue);
...

Avenues that I have looked into, but are not solutions

  • Hosting CLR in Delphi with/without JCL - example
  • http://www.blong.com/Conferences/BorConUK2002/Interop2/COMNetInterop.htm

THIS IS NOT A DUPLICATE

ChrisF was wrong to mark this as a duplicate . The referenced question and answers refer only to situations where the developer controls and writes the .Net assembly. As stated, the assembly attempting to be invoked is a third party (Saxon). The question has been satisfactorily answered, but it should not have been closed as a duplicate.

like image 632
Sean B. Durkin Avatar asked May 28 '13 06:05

Sean B. Durkin


1 Answers

Not terribly familiar with the Saxon API, but I am with Delphi, .NET and COM interoperability.

What I would suggest you do is create a facade pattern around the Saxon API in your favorite (or most tolerable) .NET language. Leave ComVisible True on those wrapper classes. Then access this wrapper assembly via COM Interop in Delphi.

You could really get away with an adapter patter, but since I am assuming you don't need to access the entire Saxon API then a facade is more appropriate.

like image 102
Jim McKeeth Avatar answered Sep 28 '22 02:09

Jim McKeeth