E_Pluribus_Unum81
E_Pluribus_Unum81

Reputation: 1

Excel 2013 (64bit) VBA String + dll

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

Answers (2)

E_Pluribus_Unum81
E_Pluribus_Unum81

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

David Heffernan
David Heffernan

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

Related Questions