Unable to pass a string from VBA (Excel) to my COM object

2

I am experimenting with creating a COM interface for my application in order to allow eg. VBA to drive certain parts of my application.

I have my COM library up and running and installed, even to the part where a routine called in Excel can be debugged in the Delphi IDE.

Here's the VBA code that I activate from Excel using a button:

Sub TestAMQMOLE_OpenProject()
  Dim vConnection As String
  Dim vAMQM As Object
  Dim vAMProject As Object

  vConnection = "$(MYSRC)\LCCAMQM38\UnitTestData\AnalyseSortingAndGrouping"
  Set vAMQM = CreateObject("LCCAMQM_AX.LCCAMQM_Application")
  vAMQM.Connect
  Set vAMQMProject = vAMQM.OpenProject(vConnection) 'This parameter does not get through
  Set vAMQMProject.Active = True
  Set vAMQMProject = Nothing


  vAMQM.Disconnect
  Set vAMQM = Nothing


End Sub

And the part in Delphi handling it looks like this:

function TLCCAMQM_Application.OpenProject(const aFolderOrAlias: WideString): ILCCAMQM_Project;
begin
  try
    Result:=TLCCAMQM_Project.Create(aFolderOrAlias); // wrapper om TdmAMEditBase
  except
    SHowMessage(ExceptionToString(ExceptObject,ExceptAddr));
  end;
end;

Where the code fails because the aFolderOrAlias parameter string is empty. I added the exception handler in order to debug outside the Delphi IDE. when debugging inside the IDE, the parameter string indeed appears as empty.

I have also tried to pass the parameter as a Variant, or const Variant (and adjusting the type library accordingly), but in that case I get a VT_RECORD variant type (0x0024) which does not make any sense to me.

Here is what the interface definition of the type library looks like.

....
 [
    uuid(EDD8E7FC-5D96-49F1-ADB7-F04EE9FED7B5),
    helpstring("Dispatch interface for LCCAMQM_Application Object"),
    dual,
    oleautomation
  ]
  interface ILCCAMQM_Application: IDispatch
  {
    [id(0x000000C9)]
    int _stdcall Connect(void);
    [id(0x000000CA)]
    int _stdcall Disconnect(void);
    [id(0x000000CB)]
    ILCCAMQM_Project* _stdcall OpenProject([in] BSTR aFolderOrAlias);
    [propget, id(0x000000CC)]
    HRESULT _stdcall Connected([out, retval] VARIANT_BOOL* Value);
  };

  [
    uuid(590DBF46-76C9-4877-8F47-5A926AFF389F),
    helpstring("LCCAMQM_Application Object")
  ]
  coclass LCCAMQM_Application
  {
    [default] interface ILCCAMQM_Application;
  };
....

I am fairly sure there must be a way to pass strings from VBA to COM objects. But after fiddling around for several hours I am lost :s.

vba
delphi
com
asked on Stack Overflow Aug 29, 2018 by H.Hasenack • edited Aug 29, 2018 by Remy Lebeau

1 Answer

0

As it turned out, ComIntern and Remy were right. I had completely misunderstood the whole stdcall and safecall interfaces.

The .ridl file now looks like this:

....
  interface ILCCAMQM_Application: IDispatch
  {
    [id(0x000000C9)]
    int _stdcall Connect(void);
    [id(0x000000CA)]
    int _stdcall Disconnect(void);
    [propget, id(0x000000CC)]
    HRESULT _stdcall Connected([out, retval] VARIANT_BOOL* Value);
    [id(0x000000CB)]
    HRESULT _stdcall OpenProject([in] BSTR aFolderOrAlias, [out, retval] ILCCAMQM_Project** Value);
  };
....

And the generated ...TLB.pas file looks like this:

....
// *********************************************************************//
// Interface: ILCCAMQM_Application
// Flags:     (4416) Dual OleAutomation Dispatchable
// GUID:      {EDD8E7FC-5D96-49F1-ADB7-F04EE9FED7B5}
// *********************************************************************//
  ILCCAMQM_Application = interface(IDispatch)
    ['{EDD8E7FC-5D96-49F1-ADB7-F04EE9FED7B5}']
    function Connect: SYSINT; stdcall;
    function Disconnect: SYSINT; stdcall;
    function Get_Connected: WordBool; safecall;
    function OpenProject(const aFolderOrAlias: WideString): ILCCAMQM_Project; safecall;
    property Connected: WordBool read Get_Connected;
  end;

// *********************************************************************//
// DispIntf:  ILCCAMQM_ApplicationDisp
// Flags:     (4416) Dual OleAutomation Dispatchable
// GUID:      {EDD8E7FC-5D96-49F1-ADB7-F04EE9FED7B5}
// *********************************************************************//
  ILCCAMQM_ApplicationDisp = dispinterface
    ['{EDD8E7FC-5D96-49F1-ADB7-F04EE9FED7B5}']
    function Connect: SYSINT; dispid 201;
    function Disconnect: SYSINT; dispid 202;
    property Connected: WordBool readonly dispid 204;
    function OpenProject(const aFolderOrAlias: WideString): ILCCAMQM_Project; dispid 203;
  end;
....

And the OpenProject now works from my internal unit test (written in delphi) as well as from Excel-VBA.

Now I am struggling with properties to set and get through Excel VBA as well as through an OleVariant in delphi. But I will have to put that in another Q.

answered on Stack Overflow Aug 30, 2018 by H.Hasenack • edited Sep 3, 2018 by H.Hasenack

User contributions licensed under CC BY-SA 3.0