1

I have been attempting to use an Agile Reference (see https://devblogs.microsoft.com/oldnewthing/20151020-00/?p=91321) created in a Delphi (XE7) COM In-process server (MTA) to pass to an Out of process COM server (STA) that the in-process server started. This should enable the out-of-process server to make calls back in to the in-process server successfully marshalling the interface pointers between the two processes.

This is the definition of the Agile Reference code. I found this code in an open source library. (I cant find it!). Perhaps a newer than XE7 version of ole32.pas might include it?

unit libagile;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses
  ComObj, {ActiveX,} StdVcl;

type
  AgileReferenceOptions = (
    AGILEREFERENCE_DEFAULT        = 0,
    AGILEREFERENCE_DELAYEDMARSHAL = 1);

  {$HPPEMIT 'DECLARE_DINTERFACE_TYPE(IAgileReference);'}
  {$EXTERNALSYM IAgileReference}
  IAgileReference = interface(IUnknown)
  ['{C03F6A43-65A4-9818-987E-E0B810D2A6F2}']
   function Resolve(const riid: TGUID;
                    out ppvObjectReference: Pointer): HResult; stdcall;

  end;
  IID_IAgileReference = IAgileReference;
  {$EXTERNALSYM IID_IAgileReference}

  function RoGetAgileReference(options: AgileReferenceOptions;
                               const riid: TGuid;
                               pUnk: IUnknown;
                               out ppAgileReference: IAgileReference): HResult; stdcall;
                               external 'Ole32.dll';
  {$EXTERNALSYM RoGetAgileReference}

implementation
end.

This seems to work when called in the in-process server. (The si.o( are just logging calls.) but the call to the out of process server fails when it tries to call Resolve on the passed interface.

procedure SetupCallback(obj:IInterface);
var
  hres : hresult;
  ref : IAgileReference;
  pref: pointer;
begin
  hres := RoGetAgileReference(  AGILEREFERENCE_DEFAULT,
                        IWTSPlugin,
                        obj,
                        ref
                        );
  if (hres = s_ok) then
    begin
      if (ref.Resolve(IID_IWTSPLUGIN,pRef)= S_OK) then
        begin
          fLocalProxy.SetAgileRef(ref);
        end
        else
          si.o('Failed Resolve hres = '+Inttostr(hres));
    end
      else
        si.o('Failed RoGetAgileReference hres = '+Inttostr(hres));

The SetAgileRef is a method in the Out Of Process server. However calling Resolve on the ref value passed in call fails usually with a Stack Overflow.

David Bolton
  • 150
  • 2
  • 10
  • This interface is also not delivered in the latest Delphi version Sydney 10.4.0 (even not outside the Winapi.OLE2 unit). – Schneider Infosystems Ltd Jul 28 '20 at 15:59
  • It seems that [RoGetAgileReference](https://docs.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-rogetagilereference) can only be used to pass around interfaces to apartments **within the same process** *("The agile reference can be passed to another apartment within the same process")*. And from Raymond: *"What if I need to marshal an object from one thread to another thread in the same process?"* The out-of-process COM stuff has always been a bit of voodoo, but perhaps that's what you're hitting here. What's the HRESULT? – Ian Boyd Jul 29 '20 at 16:07
  • You an also try `CoMarshallInterface`, or registering your object in the **Running Object Table** (ROT) if the process is on the same machine (https://stackoverflow.com/a/5431017/12597). I can tell you that these cross-process/machine proxying methods need to have a full Type Library registered for your COM object - COM has to know all the arguments, and their types, so it can marshal and unmarshal the arguments when you call methods across apartments. And if you don't have a TLB registered, you can implement IMarshal, and manually do the marshalling. – Ian Boyd Jul 29 '20 at 16:19
  • Yes it was between threads (MTA and STA) on the same machine but in different processes. I do have type libraries. – David Bolton Jul 30 '20 at 14:49

0 Answers0