我有一个64位Delphi(XE4)dll。我从Excel VBA中调用它。
我使用以下技巧:http://www.devx.com/tips/Tip/37587
适用于32位和64位excel-2010,但不适用于excel-2013
StrDataSizePtr^:=Length(tmpStr);//Access Violation here
可能是什么问题? excel-2013 vba有新的String格式吗?
谢谢!
编辑:
的Delphi
{$IFDEF WIN64}
TPtrLong = UInt64;
{$ELSE}
TPtrLong = Longword;
{$ENDIF}
procedure StrToVBAStr(Str : String;VAR VBAStr : PAnsiChar);
VAR
VBAStrPtr : TPtrLong absolute VBAStr;
ResStrSizePtr : PLongword;
begin
if Length(Str)>Integer(StrLen(VBAStr))
then raise Exception.Create('StrToVBAStr : '+IntToStr(Length(Str))+'>'+IntToStr(StrLen(VBAStr)));
ResStrSizePtr:=Ptr(VBAStrPtr-4);//this points to VBA String size
VBAStr:=StrPLCopy(VBAStr,Str,Length(Str));//copy to VBAStr-be
ResStrSizePtr^:=Length(Str);//set VBAStr length
end;
function GetLastError(VAR Error : PAnsiChar) : Longint; stdcall;
VAR
sError : String;
begin
TRY
Result := _GetLastError(sError);
StrToVBAStr(sError, Error);
EXCEPT
Result := -1;
END;
end;
VBA
Private Declare PtrSafe Function XLDLL_GetLastErrorA Lib "XL.dll" Alias "GetLastError" ( _
ByRef Result As String) As Long
Public Sub XLDLL_Error(Optional ByVal Source As String = "")
Dim XLErr As String
XLErr = Space(1001)
If XLDLL_GetLastErrorA(XLErr) <> -1 Then
XL_LastError = XLErr
If XL_LastError <> "" Then
Err.Raise vbObjectError + 1000, Source, XL_LastError
End If
Else
Err.Raise vbObjectError + 1000, "XLDLL_Hiba", "XLDLL_GetLastErrorA hiba"
End If
End Sub
答案 0 :(得分:0)
该代码从未正确。它可能在过去偶然发挥作用。 VBA字符串的内部私有实现可能已更改。或者它可能保持不变,你的运气刚刚耗尽。
在任何情况下,正确的解决方案是停止依赖VBA字符串的私有内部实现细节。将字符串从本机代码传递到VBA就足够了。这样做:
<强>的Delphi 强>
procedure GetString(Str: PAnsiChar; var Len: Integer); stdcall;
var
Value: AnsiString;
begin
Value := ...;
StrLCopy(Str, PAnsiChar(Value), Len);
Len := Min(Len, Length(Value));
end;
<强> VBA 强>
Private Declare PtrSafe Sub GetString Lib "XL.dll" ( _
ByVal str As String, ByRef len As Long)
....
len = 1024
buff = Space(len)
GetString(buff, len)
buff = Left(buff, len)
答案 1 :(得分:0)
看起来问题是由其他Excel插件引起的。 在纯粹的新Excel-2013安装上,它可以正常工作。 从Excel-2013中删除插件后,错误就消失了。
(VBA“字符串黑客”仍可在Excel-2013中使用)