【问题标题】:Unable to pass a string from VBA (Excel) to my COM object无法将字符串从 VBA (Excel) 传递到我的 COM 对象
【发布时间】:2019-02-04 09:42:42
【问题描述】:

我正在尝试为我的应用程序创建一个 COM 接口,以允许例如。 VBA 来驱动我的应用程序的某些部分。

我已经启动并运行并安装了我的 COM 库,甚至可以在 Delphi IDE 中调试 Excel 中调用的例程的部分。

这是我使用按钮从 Excel 激活的 VBA 代码:

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

Delphi 中处理它的部分如下所示:

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;

由于aFolderOrAlias 参数字符串为空而导致代码失败。我添加了异常处理程序以便在 Delphi IDE 之外进行调试。在IDE内部调试时,参数字符串确实显示为空。

我还尝试将参数作为Variantconst Variant 传递(并相应地调整类型库),但在这种情况下,我得到了一个VT_RECORD 变体类型(0x0024),它不会产生任何对我有感觉。

这是类型库的接口定义的样子。

....
 [
    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;
  };
....

我很确定一定有一种方法可以将字符串从 VBA 传递到 COM 对象。但是在摆弄了几个小时后,我迷路了:s。

【问题讨论】:

  • 不应该ILCCAMQM_Project*[out, retval] 而不是返回类型?在我看来,OpenProject 应该返回一个 HRESULT
  • 在 IDL 中,是的。您必须使用带有HRESULT 返回值的[out, retval] 参数:HRESULT _stdcall OpenProject([in] BSTR aFolderOrAlias, [out,retval] ILCCAMQM_Project** Result);。在 Delphi 代码中,将 OpenProject() 声明为 safecall 并带有 ILCCAMQM_Project 返回值且没有输出参数:function OpenProject(const aFolderOrAlias: WideString): ILCCAMQM_Project; safecall;OpenProject() 引发异常而不捕获它们,safecall 会将其转换为 HRESULT 和使用异常详细信息填充GetErrorInfo()。与Connected() 相同。

标签: vba delphi com


【解决方案1】:

事实证明,ComIntern 和 Remy 是对的。我完全误解了整个stdcallsafecall 接口。

.ridl 文件现在如下所示:

....
  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);
  };
....

生成的 ...TLB.pas 文件如下所示:

....
// *********************************************************************//
// 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;
....

OpenProject 现在可以通过我的内部单元测试(用 delphi 编写)以及 Excel-VBA 运行。

现在我正在努力使用属性来设置和通过 Excel VBA 以及通过 delphi 中的 OleVariant。但我必须把它放在another Q

【讨论】:

  • 事实证明,我的属性无法访问是由于我的类是从 tAutoIntfObject 而不是 TAutoObject 派生的,所以现在也清除了。
猜你喜欢
  • 2023-04-11
  • 1970-01-01
  • 2014-10-08
  • 1970-01-01
  • 2011-11-23
  • 2011-06-28
  • 1970-01-01
  • 1970-01-01
  • 2014-12-05
相关资源
最近更新 更多