VBA OSX 上的 strerror / strncpy 问题

VBA trouble with strerror / strncpy on OSX

我的 Excel 电子表格每次使用此代码时都会锁定。通常这意味着某种声明或调用错误,(无知错误)但我还没有确定它。

此示例 VBA 函数 SystemErrorText 应该 return errno 2 的系统错误消息的文本:找不到文件。它没有:它从不从对 strncpy

的调用 returns
'char *strerror(int errnum);
Public Declare Function osx_strErrorlp Lib "libc.dylib" Alias "strerror" _
    (ByVal errnum As Long) As Long

'char *strncpy(char * restrict dst, const char * restrict src, size_t len);
Public Declare Function osx_strncpy Lib "libc.dylib" Alias "strncpy" _
    (ByVal strDestination As String, ByVal strSource As String, destlen As Long) As Long

Public Function SystemErrorText() As String
Dim ErrorText As String
Dim nLen As Long
Dim longpointer As Long
Dim lngptr2 As Long

longpointer = osx_strErrorlp(2)
ErrorText = String(256, Chr(0))
nLen = 255
lngptr2 = osx_strncpy(ErrorText, longpointer, nLen)
SystemErrorText = ErrorText

End Function

谁能看出我做错了什么?我从 strerror 得到一个指针,我认为它是正确的(也许错误在那里?),但我不确定这是否重要:我只是想从该位置复制一些字节。

我不能保证我作为注释包含的 c 声明对 OS X: 我已经得到它们,但我没有保证它们有效的来源对于 OS X。我正在为 Mac 使用 Excel 的 32 位版本:指针是 32 位的,long 也是。与 Excel 的 Windows 版本不同,Mac 版本无法防止调用库函数时出现堆栈错误:它只会崩溃。出于某种原因,err.LastDLLerror 未连接到 errno(对于此示例而言并不重要)。

此声明的使用方式是错误的:

Public Declare Function osx_strncpy Lib "libc.dylib" Alias "strncpy" _
    (ByVal strDestination As String, ByVal strSource As String, destlen As Long) As Long

"strSource" 声明为 ByVal 字符串。这意味着指向空终止字符串的指针将传递给 libc 函数(好)。但这也意味着 VBA 代码将接受并需要 BSTR 参数(错误)。

调用函数的地方:

lngptr2 = osx_strncpy(ErrorText, longpointer, nLen)

... longpointer 值首先隐式转换为 BSTR。然后将该 bSTR 的值(包含指针值的 文本表示的空终止字符串的 地址)传递给 libc 函数。

所以strncpy是从本地临时内存区域复制到目的地,而不是从错误字符串复制到目的地。为什么这导致 Excel 崩溃是未知的:在同样的情况下,strlcpy 不会崩溃。但这并不重要:即使有效,也不是我们想要的。

请注意,该声明不是 "wrong",它适用于

text1 = "A"
text2 = String(2,chr(0))
osx_strncpy(text2, text1, Len(text1))

-- 这不是我们想要的。要求是接受指针值的函数:

Public Declare Function osx_strncpy_lp Lib "libc.dylib" Alias "strncpy" _
    (ByVal strDestination As String, ByVal strSource_lp As Long, destlen As Long) As Long

您甚至可以通过声明一个字符串对象,然后用您要使用的指针值覆盖它的内部值,使原始声明生效。但是如果你这样做了,你可以只使用 VBA 赋值语句来复制乱七八糟的字符串对象