Hallo Community,
ich möchte Euch erneut um Hilfe bitten! Bei folgender Aufgabenstellung komme ich leider nicht weiter:
Aus einer Delphi-
DLL möchte ich einen StringVektor an Excels VBA übergeben. Dazu habe ich eine funktionierende Lösung entwickelt, die folgendermaßen aussieht:
Delphi XE5 Professional
Zielplattform: 32-Bit-
DLL
Excel: 2016
Delphi-Quellcode:
library Delphi_String_for_Excel_Test;
uses
System.ShareMem,
System.SysUtils,
System.Classes,
System.AnsiStrings
;
{$R *.res}
Type
ExcelLongInt = Int32; // {4 Bytes}
CONST
AnsiString_Vektor_GLOBAL: Array [0..3] of AnsiString = ('1: Erster String',
'2: Das ist der ZWEITE String!',
'3: ...und hier ist der DRITTE!',
'4: Schlußlicht-String...');
Procedure AnsiString_To_Excel(S: PAnsiChar; i: ExcelLongInt); StdCall;
// Aufgabe -> Einen Delphi-AnsiString-Vektor ZEILENWEISE an Excel-VBA übertragen
// S: PAnsiChar : zu übertragender Strings
// i: ExcelLongInt : der i-te String im globalen Vektor
VAR
P: AnsiString;
Begin
P:= AnsiString_Vektor_GLOBAL[i]; // Rückgabewert
System.AnsiStrings.StrPLCopy(S, P, Length(P)); // Excels String-Array wird überschrieben
End;{AnsiString_To_Excel}
{-----------------------}
Exports
AnsiString_To_Excel
;
begin
end.
Auf Excels Seite sieht der Code wie folgt aus:
VBA-Code:
Delphi-Quellcode:
Option Explicit
Private Declare Sub AnsiString_To_Excel Lib "Delphi_String_for_Excel_Test.dll" _
(ByVal A
As String, ByVal i
As Long)
'
Es funktioniert!
Public Function GetDelphiStrings(Anzahl As Long)
' Zeilenweiser Aufruf der
DLL-Routine AnsiString_To_Excel
'
Es funktioniert!
Dim Vektor() As String
Dim NULStr As String
Dim i As Long
i = 1 'Wichtig: sonst kommen u.U. sinnlos hohe Werte beim Start und der Vektor
in der
DLL steigt aus: RangeCheckError!
ReDim Vektor(1
To Anzahl, 1
To 1) '
SpaltenVektor anpassen
NULStr = String(100, vbNullChar) 'Excel MUSS den Speicherbereich zur Verfügung stellen:
in der
DLL wird dieser nur gepatcht!
For i = 1
To Anzahl
Vektor(i, 1) = NULStr
AnsiString_To_Excel Vektor(i, 1), i - 1 '
!!! -1: Delphi: NULL-basiert!
Next
GetDelphiStrings = Vektor
End Function
Der Schönheitsfehler dieser Lösung besteht darin, daß ich die Strings des StringVektors ZEILENWEISE einlese, d.h. von VBA aus wird die
DLL-Routine AnsiString_To_Excel n-mal aufgerufen.
Meine Idee für eine Verbesserung sieht folgendermaßen aus:
VBA-Code:
Delphi-Quellcode:
Private Declare Sub AnsiStringVektor_To_Excel Lib "Delphi_String_for_Excel_Test.dll" _
(ByVal A
As String, ByVal n_Anzahl
As Long)
'
Es funktioniert NICHT!
Public Function GetDelphiStringVektor(Anzahl As Long)
' EINMALIGER Aufruf der
DLL-Routine AnsiStringVektor_To_Excel
'
Es funktioniert!
Dim Vektor() As String
Dim NULStr As String
Dim i As Long
i = 1 'Wichtig: sonst kommen u.U. sinnlos hohe Werte beim Start und der Vektor
in der
DLL steigt aus: RangeCheckError!
ReDim Vektor(1
To Anzahl, 1
To 1) '
SpaltenVektor anpassen
NULStr = String(100, vbNullChar) 'Excel MUSS den Speicherbereich zur Verfügung stellen:
in der
DLL wird dieser nur gepatcht!
For i = 1
To Anzahl
Vektor(i, 1) = NULStr
Next
AnsiString_To_Excel Vektor(1, 1), Anzahl
GetDelphiStringVektor = Vektor
End Function
Und die
DLL habe ich um Folgendes erweitert:
Delphi-Quellcode:
Procedure AnsiStringVektor_To_Excel(S: PAnsiChar; n_Anzahl: ExcelLongInt);
StdCall;
// Aufgabe -> Einen Delphi-AnsiString-Vektor auf EINMAL an Excel-VBA übertragen
// S: PAnsiChar : Erstes Element des zu zu übertragenden StringVektors
// n_Anzahl: ExcelLongInt : Gesamtzahl der Strings im StringVektor
VAR
Vektor:
Array of PAnsiChar
ABSOLUTE S;
P : AnsiString;
i : Integer;
Begin
For i:= 1
To n_Anzahl
Do // Excel: 1-basiertes Array
Begin
P:= AnsiString_Vektor_Global[i-1];
// -1: Delphi: 0-basiertes Array
System.AnsiStrings.StrPLCopy(Vektor[i], P, Length(P));
// --> Access violation
// System.AnsiStrings.StrCopy(PAnsiChar(Vektor[i]), PAnsiChar(P)); // --> Access violation
End;
End;
{AnsiStringVektor_To_Excel}
{-----------------------------}
...
Exports
...
, AnsiStringVektor_To_Excel
Leider erhalte ich aus der Procedure AnsiStringVektor_To_Excel stets "
Access violation".
Im gezippten Anhang befinden sich folgende dre einsatzferige Dateien:
- Delphi_String_for_Excel_Test.dpr
- Delphi_String_for_Excel_Test.dll
- Delphi_String_for_Excel_Test.xlsm (s. Benutzungshinweise)
Was mache ich falsch? Geht es überhaupt durch nur EINEN EINZIGEN Aufruf oder nur ZEILENWEISE?
Vielen Dank für Eure Hilfe im Voraus!
Gruß
Andreas