VBA与COM DLL中函数对象的实现

在VBA编程中,指针的支持非常有限,尤其是函数指针。这在进行泛型编程时尤其不便。为了解决这一问题,可以利用C++ ATL技术,创建一个COM DLL,使得VBA能够通过函数对象(functors)来调用函数。本文将详细介绍如何实现这一过程,包括C++的实现细节和VBA的使用方式。

VBA中的函数对象

VBA本身并不支持函数指针,但可以通过COM DLL来实现类似的功能。以下是一个VBA代码示例,展示了如何初始化并调用一个函数对象:

Dim opfn As Functor Set opfn = New_Functor(AddressOf MyFunction, retvoid_2_args) Call opfn.call_retvoid_2("This works", "fine!")

这段代码首先创建了一个函数对象,然后通过该对象调用了一个函数。

C++ATL实现

项目使用C++ATL编写,并编译为COM DLL。导出的Functor对象可以在VBA代码中使用,以存储函数地址,并在之后通过匹配函数类型的Functor对象的方法来调用它。以下是IDL声明和示例函数调用方法:

interface IFunctor : IDispatch { [id(1), helpstring("Hooks on a function")] HRESULT HookFunction([in] LONG fnAddress, [in] enum FuncType functionType); [id(8), helpstring("Calls Function that a)Retruns VARIANT b)Takes 2 arguments")] HRESULT call_retvar_2([in, out, optional] VARIANT* Arg1, [in, out, optional] VARIANT* Arg2, [out, retval] VARIANT*); }

这些函数类型在Functor.h中定义:

typedef HRESULT (__stdcall *pfn_retvoid_0)(void); typedef HRESULT (__stdcall *pfn_retvoid_1)(VARIANT*); typedef HRESULT (__stdcall *pfn_retvoid_2)(VARIANT*, VARIANT*); // 更多函数类型...

这些函数类型对应于FuncType枚举的成员,该枚举也从DLL中导出:

enum FuncType { retvoid_0_args, retvoid_1_args, retvoid_2_args, // 更多函数类型... };

DLL还导出了一个初始化器类,用于模拟带参数的构造函数。例如,New_Functor()返回一个新初始化的Functor (IFunctor)对象。

使用代码

源代码中包含的VBA_Functors_Test.xls文件包含了使用Functor对象的一些示例。要正确地从VBA初始化Functor对象,需要进行以下步骤:

  • 定义并初始化一个Functor变量。
  • 挂钩到一个现有的VBA函数。该函数必须是预定义类型之一,并且需要通过HookFunction()的第二个参数传入正确的函数类型。

以下是一个VBA代码示例,展示了如何使用New_Functor()函数:

Public Sub UseFunctors() Dim ofn As Functor Set ofn = New_Functor(AddressOf SimpleFunction, retvar_1_args) Dim vbmRes As VbMsgBoxResult vbmRes = ofn.call_retvar_1("Display this!") End Sub

这段代码首先创建了一个函数对象,然后通过该对象调用了一个函数。

安全性和注册

在企业环境中,安全策略可能会与COM组件的注册发生冲突。通常,这些组件是在HKEY_LOCAL_MACHINE下注册的,而普通用户没有写入权限。通过在ATL中使用AtlSetPerUserRegistration(true),可以将组件注册在HKEY_CURRENT_USER下,从而解决这个问题。

以下是DllRegisterServer的定义:

STDAPI DllRegisterServer(void) { ATL::AtlSetPerUserRegistration(true); HRESULT hr = _AtlModule.DllRegisterServer(); return hr; }

com_definitions.h文件中定义了HRESULT,它通常用作COM方法的返回值。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485