Reputation: 1
I've got a 64bit Delphi (XE4) dll. I call it from Excel VBA.
I use the following trick : http://www.devx.com/tips/Tip/37587
It works for 32bit and 64bit excel-2010, but not with excel-2013
StrDataSizePtr^:=Length(tmpStr);//Access Violation here
What can be the problem? Does excel-2013 vba has new String format?
Thank You!
EDIT:
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
Upvotes: 0
Views: 1149
Reputation: 1
It looks like the problem was caused by an other Excel plugin. On a pure new Excel-2013 install it works fine. After removing plugins from the Excel-2013, the error gone.
(The VBA "string hack" still works in Excel-2013)
Upvotes: 0
Reputation: 612993
That code has never been correct. It might have worked by chance in the past. It's possible that the internal private implementation of the VBA string has been changed. Or it is possible that it has stayed the same and your luck has just run out.
In any case, the correct solution is to stop relying on the private internal implementation detail of the VBA string. Passing a string from native code to VBA is simply enough. Do it like this:
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)
Upvotes: 1