6

我目前正在使用类似于以下的 VBA 代码来指定共享库的位置,以用于从 Office 应用程序到桌面应用程序的通信(传递字符串)。VBA 代码/宏需要存在于加载项 (.ppa) 中。

Private Declare Sub sharedLibPassString CDecl Lib "/Users/myUserName/Library/Application Support/myCompanyName/MySharedLib.dylib" Alias "PassString" (ByVal aString As String)

在来自 VBA 宏的代码中,我可以执行以下操作。

Call sharedLibPassString(myString)

我的通信正常,但我想/Users/myUserName/用当前用户的主目录替换该部分。通常在 Mac 上,您会指定~/Library/Application Support/...,但~/语法不起作用,会产生“找不到文件”运行时错误。

我发现使用以下环境变量方法可以获得我~/需要的位置:

Environ("HOME")

但是,我看不出有一种方法可以使这部分CDecl Lib陈述成为可能,因为据我所知,Environ它是在运行时评估的。

~/有没有办法在 VBA的用户主目录()中指定共享库的位置?


以下是关于我的环境/方法的一些说明:

  • 我使用的是 Mac,但我相信如果有解决方案,它会在 PC 上类似。
  • 我认为这无关紧要,但我使用的 Office 应用程序是 PowerPoint (2011)。
  • 我尝试访问应用程序支持目录中的区域而不是共享库的默认位置的原因是因为我希望桌面应用程序将共享库放置在没有安装程序的位置,并且不需要用户或管理员的权限。如果有更好的解决方案或位置来完成相同的任务,这也将非常有帮助。
4

2 回答 2

2

我没有Mac,所以这是一个不完整的答案,我不知道它是否会有所帮助,但这是一些想法。

我知道在 Windows 上,VB 不会加载外部库,直到您第一次尝试调用用它声明的函数,如果您在声明语句中仅指定文件名,它将使用系统路径来查找它。一旦我做了你正在做的同样的事情,从动态路径加载一个库,只指定一个文件名,然后在加载它之前进行系统 API 调用以将当前工作目录设置为库的目录。更改 PATH 环境变量也可能有效。

第二个想法:您可以将路径硬编码到 /tmp 目录中的文件名;然后在加载之前自动将所需的库复制到该位置。注意文件正在被另一个进程使用,但这只是一个错误,如果它与您想要的文件版本不同。

于 2012-10-30T17:53:17.690 回答
2

很抱歉给了一个很长的回应,我只是想确保我解释得很好。

从这个页面(声明声明的剖析)我们读到

Lib 关键字指定哪个 DLL 包含该函数。请注意,DLL 的名称包含在Declare 语句中的字符串中。(重点补充)

从实验来看,如果我尝试提供除字符串常量之外的任何内容,VBE 会责骂我。

我知道的唯一解决方法需要在运行时重写字符串常量。

这是一个如何做到这一点的示例:假设您的 delaration 声明位于当前项目的 Module1 中,并且您故意在模块顶部以这种格式编写声明:

Private Declare Sub sharedLibPassString CDecl Lib _
"/Users/myUserName/Library/Application Support/myCompanyName/MySharedLib.dylib" _
Alias "PassString" (ByVal aString As String)

您可以通过代码访问该模块(需要开发人员宏设置下列出的信任中心中的 VBA 权限):

Dim myModule
set myModule = ActivePresentation.VBProject.VBComponents("Module1").CodeModule

获得 CodeModule 后,可以直接替换第 2 行:

myModule.ReplaceLine 2, Environ("HOME") & " _"

任务完成!

如果你这样做,你将需要在尝试调用你声明的 sub 之前更新路径。执行中必须有一个中断,以使 VBA 能够识别更改。此外,您将无法在中断模式下修改代码。

现在,如果我这样做,我想确保我替换了正确的行,而不是破坏代码。您可以通过调用它来检查第二行的内容,myModule.Lines(2,1)这将返回该行的字符串值。

但是,这是一个更强大的解决方案,它将找到正确的行,然后替换它(假设 myModule 已经按上面列出的方式定义):

Dim SL As Long, EL As Long, SC As Long, EC As Long
Dim Found As Boolean
SL = 1     ' Start on line 1
SC = 1     ' Start on Column 1
EL = 99999 ' Search until the 99999th line
EC = 999   ' Search until the 999th column
With myModule
    'If found, the correct line will be be placed in the variable SL
    'Broke search string into two pieces so that I won't accidentally find it.
    Found = .Find("/Users/myUserName/Library/Application Support/myCompanyName/" & _
             "MySharedLib.dylib", SL, SC, EL, EC, True, False, False)
    If Found = True Then
        'Replace the line with the line you want, second paramater should be a string of the value.
        .ReplaceLine SL, Environ("HOME") & " _"
    End If
End With
于 2012-10-30T16:33:12.707 回答