AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein .NET-Framework (managed code) C# Stringübergabe in eine Delphi Win32-DLL
Thema durchsuchen
Ansicht
Themen-Optionen

Stringübergabe in eine Delphi Win32-DLL

Ein Thema von little_budda · begonnen am 18. Aug 2012 · letzter Beitrag vom 20. Aug 2012
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von little_budda
little_budda

Registriert seit: 5. Mai 2006
Ort: Velbert
246 Beiträge
 
Delphi 2006 Professional
 
#1

Stringübergabe in eine Delphi Win32-DLL

  Alt 18. Aug 2012, 13:05
Hallo,

ich veruche eine Funktion aus einer Delphi Win32 DLL unter C# aufzurufen.
Ich muss hier zwei strings übergeben und scheitere daran kläglich.
In meiner DLL kommt immer nur Schrott an.

Hier in der Forensuche finden sich zwar einige Beträge die Stringübergaben behandeln,
aber die Tipps bringen mich nicht nach vorn.

Meine C# Implemetierung:
Code:
  [return: MarshalAs(UnmanagedType.I4)]
  [DllImport("wsa.dll", CharSet = CharSet.Auto)]
  static extern Int32 ConvertArchiveToXml(
    [MarshalAs(UnmanagedType.BStr)] string archivePath,
    [MarshalAs(UnmanagedType.BStr)] string xmlPath);
// Für das Marshalling habe ich auch schon ".LPStr" und ".LPWStr" ausbrobiert.
// Leider mit gleichem Ergebnis
Unter Delphi habe ich die Funktion wie folgt aufgebaut
Delphi-Quellcode:
library wsa;
...
function ConvertArchiveToXml(achivePath: PAnsiChar; xmlPath: PAnsiChar): integer;
// In der Deklaration habe ich bereits PChar und widestring ausprobiert.
var amountOfDataLines : integer;
    lastErrorCode : integer;
begin
  // Testausgaben in eine lokale Protokolldatei um die Übergaben in die DLL zu prüfen
  SetLogItem('Archiv: ' + archivePath);
  SetLogItem('XML: ' + xmlPath);

  try
    result := ExtractArchiveContentToTable(archivePath);
// (Die Funktion liefert einen INT)
  except
    result := -1;
  end;
end;

...

exports
  ConvertArchiveToXml,
  initDLL,
  freeDLL;
...
Was bitte mache ich denn falsch?
Holger
Glück findet sich nicht im Code
Gefahren werden ist nur solange schön wie man selbst nicht lenken möchte ...
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#2

AW: Stringübergabe in eine Delphi Win32-DLL

  Alt 19. Aug 2012, 06:25
Wo ist der Einsprungspunkt?
Zumindest kann ich den in deinem Code nicht entdecken.

Beispiel aus meiner DLL!
C# Seite
Code:
        //BASSVIS_GetVersion
        public static string BASSVIS_GetVersion()
        {
            IntPtr ptr = BASSVIS_GetVersionPtr();
            if (ptr != IntPtr.Zero)
            {
                return Marshal.PtrToStringAnsi(ptr);
            }
            return null;
        }
        [DllImport("bass_vis.dll", EntryPoint = "BASSVIS_GetVersion", CharSet = CharSet.Auto)]
        private static extern IntPtr BASSVIS_GetVersionPtr();
Delphi Seite
Delphi-Quellcode:
function BASSVIS_GetVersion: PAnsiChar; stdcall;

const
  cverfor = '%d.%d.%d.%d';

var
  ver : TBASSVIS_VERSION;
  str : string;
begin
  ver := GetVersionNumber;
  str := format(cverfor,[ver.Major,ver.Minor,ver.Special,ver.Build]);
  result := PAnsiChar(Ansistring(str));

end;

gruss

Geändert von EWeiss (19. Aug 2012 um 06:42 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.582 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: Stringübergabe in eine Delphi Win32-DLL

  Alt 19. Aug 2012, 10:47
Das Problem ist einfach das fehlende stdcall, das in dem Beispiel von EWeiss drin ist. Denn ohne Angabe der Aufrufkonvention wird bei .NET stdcall benutzt.

@EWeiss:
Einen PAnsiChar zurückzugeben ist mutig...
Wenn der Speicher bei der Verwendung in der aufrufenden Prozedur zufällig schon überschrieben ist, knallt es...
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
Benutzerbild von Bernhard Geyer
Bernhard Geyer

Registriert seit: 13. Aug 2002
17.196 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: Stringübergabe in eine Delphi Win32-DLL

  Alt 19. Aug 2012, 10:52
Bei D2006 sollte man auch kein CharSet.Auto verwenden. Hier wäre CharSet.Ansi angebracht.

Besser wäre gleiche PWideChar zu verwenden und alles gleich Unicode-Sicher zu realisieren. oder willst du unbedingt in 2012 noch Win9x unterstützen?
Windows Vista - Eine neue Erfahrung in Fehlern.
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#5

AW: Stringübergabe in eine Delphi Win32-DLL

  Alt 19. Aug 2012, 10:53
Zitat:
Wenn der Speicher bei der Verwendung in der aufrufenden Prozedur zufällig schon überschrieben ist, knallt es...
Solange wie ich meinen NetWrapper verwende hat das noch nie in irgendeiner Anwendung probleme bereitet.
Und geknallt hat es schon gar nicht

Ist doch die frage wie meine Classe in der die Funktion implementiert ist aufgebaut ist.
Um so eine Aussage treffen zu können muss man den gesamten Code des Wrappers gesehen habe.
Aber der ist closed Source.

Code:
    [SuppressUnmanagedCodeSecurity]
    public sealed class BassVis
    {
Zitat:
Bei D2006 sollte man auch kein CharSet.Auto verwenden. Hier wäre CharSet.Ansi angebracht.
Schon mal daran gedacht das seine DLL unter umständen auch mit D7 verwendet werden könnte?

Zitat:
Das Problem ist einfach das fehlende stdcall
Sollte man sich grundsätzlich angewöhnen wenn es um exports geht.

gruss

Geändert von EWeiss (19. Aug 2012 um 11:04 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.582 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: Stringübergabe in eine Delphi Win32-DLL

  Alt 19. Aug 2012, 12:04
Ist doch die frage wie meine Classe in der die Funktion implementiert ist aufgebaut ist.
Um so eine Aussage treffen zu können muss man den gesamten Code des Wrappers gesehen habe.
Der Speicher, den du zurücklieferst, ist jedenfalls schon freigegeben, wenn der Funktionsaufruf zurückkehrt. (Durch die Referenzzählung des Strings dahinter)
Insofern ist der Rest des Codes ziemlich egal. Es funktioniert nur deshalb, weil an der Stelle im Speicher nichts geschrieben wird bis der String bei dir umkopiert ist. (Zum Beispiel durch Zuweisung an einen String.)
Sich darauf zu verlassen ist aber nicht unbedingt sinnvoll.

// EDIT:
Um hier keine unbewiesenen Behauptungen zu posten... kleines Beispiel:
Delphi-Quellcode:
function Test(const Value: string): PChar;
begin
  Result := PChar(DupeString(Value, 10));
end;

procedure TForm240.FormCreate(Sender: TObject);
var
  TestResult1, TestResult2: PChar;
begin
  TestResult1 := Test('a');
  TestResult2 := Test('b');
  ShowMessage(TestResult1);
  ShowMessage(TestResult2);
end;
Du wirst sehen, dass (zumindest unter XE) zweimal 10xb ausgegeben wird. Einfach weil die selbe Speicheradresse wiederverwendet wird bevor der erste String ausgegeben wird... Und das ist ja auch vollkommen korrekt, da der Speicherbereich schon wieder freigegeben ist. Dass darauf noch ein Pointer existiert, darf nicht passieren. Deshalb ist der Code so schlicht fehlerhaft.
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!

Geändert von jaenicke (19. Aug 2012 um 12:14 Uhr)
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#7

AW: Stringübergabe in eine Delphi Win32-DLL

  Alt 19. Aug 2012, 12:27
Mag ja alles sein..

Aber ich bin ja auch kein Studierter .. solange es funktioniert und keine Fehlermeldungen seitens
der Anwender kommen lasse ich es erstmal so wie es ist.

Letztendlich wollte ich dem Thread ersteller helfen.
Ob er davon etwas annimmt kann mir am ende egal sein.

gruss
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.582 Beiträge
 
Delphi 11 Alexandria
 
#8

AW: Stringübergabe in eine Delphi Win32-DLL

  Alt 19. Aug 2012, 12:35
solange es funktioniert und keine Fehlermeldungen seitens
der Anwender kommen lasse ich es erstmal so wie es ist.
Da weißt du ja auch, dass es trotzdem zufällig funktioniert.
Ich meinte das auch eher für die Zukunft. Bei anderem Code funktioniert es vielleicht mal nicht und du suchst dir nen Wolf nach dem Fehler.

Letztendlich wollte ich dem Thread ersteller helfen.
Ob er davon etwas annimmt kann mir am ende egal sein.
Damit das nicht als gutes Beispiel stehen bleibt, habe ich ja auch hauptsächlich etwas dazu geschrieben. Mit dem stdcall hattest du ja im Beispiel die entscheidende Stelle auch drin.
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#9

AW: Stringübergabe in eine Delphi Win32-DLL

  Alt 19. Aug 2012, 13:08
Zitat:
Ich meinte das auch eher für die Zukunft. Bei anderem Code funktioniert es vielleicht mal nicht und du suchst dir nen Wolf nach dem Fehler.
Danke für deine Informationen bezgl. meines Fehlers.
Möchte ja nicht Undankbar erscheinen.

gruss
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.063 Beiträge
 
Delphi 12 Athens
 
#10

AW: Stringübergabe in eine Delphi Win32-DLL

  Alt 19. Aug 2012, 13:29
// EDIT:
Um hier keine unbewiesenen Behauptungen zu posten... kleines Beispiel:
Delphi-Quellcode:
function Test(const Value: string): PChar;
begin
  Result := PChar(DupeString(Value, 10));
end;

procedure TForm240.FormCreate(Sender: TObject);
var
  TestResult1, TestResult2: PChar;
begin
  TestResult1 := Test('a');
  TestResult2 := Test('b');
  ShowMessage(TestResult1);
  ShowMessage(TestResult2);
end;
Du wirst sehen, dass (zumindest unter XE) zweimal 10xb ausgegeben wird. Einfach weil die selbe Speicheradresse wiederverwendet wird bevor der erste String ausgegeben wird... Und das ist ja auch vollkommen korrekt, da der Speicherbereich schon wieder freigegeben ist. Dass darauf noch ein Pointer existiert, darf nicht passieren. Deshalb ist der Code so schlicht fehlerhaft.
Das aber auch nur, wenn der Speicher in der Zwischenzeit nicht wieder (komplett) freigegeben oder überschrieben wird.
Denn FastMM behält sich Speicher noch eine Weile, um ihn schneller wiederverwenden zu können und nicht jedesmal langwierig bei Windows beantragen zu müssen.

DupeString liefert eine Stringvariable zurück, wofür Delphi eine temporäre Variable anlegt, welche bei Funktionsende wieder freigegeben wird.
Delphi-Quellcode:
function Test(const Value: string): PChar;
var
  Temp: string;
begin
  Temp := DupeString(Value, 10);
  Result := PChar(Temp);
end; // und im FunktionsENDe steht quasi ein Temp := '';
Und es ist Zufall, wenn hier wieder die selbe PChar-Adresse zurückgegeben wird.
Nämlich nur dann, wenn FastMM zufällig den selben Speicherbereich für den Result-String von DupeString wiederverwendet. (was bei einer so einfachen Funktion und bei SingleThreadding zufällig etwas öfters passieren kann, da die Berechnung/Ermittling des nächst freien Speicherblocks ja gleich abläuft)
Tipp: Versuch es mal mit einem größeren String, wie z.B. DupeString(Value, 1000000000); , denn da ist es wahrscheinlich, daß FastMM den "großen" Speicher sofort wieder an Windows zurückgibt.

Sowas wäre eher möglich, aber das ist natürlich nicht für Multithread, also nicht für mehrere gleichzeitige Aufrufe dieser Funktion, da es nur einen StringSpeicher gibt.
Delphi-Quellcode:
var
  Test_Result: string; // den String auch noch nach dem Funktionsende erhalten

function Test(const Value: string): PChar;
begin
  Test_Result := DupeString(Value, 10);
  Result := PChar(Test_Result);
end;

procedure TForm240.FormCreate(Sender: TObject);
var
  TestResult1, TestResult2: string; // Rckgabewerte sofort in einen String umwandeln, also kopieren
begin
  TestResult1 := Test('a');
  TestResult2 := Test('b');
  ShowMessage(TestResult1);
  ShowMessage(TestResult2);
end;
Einfacher ist ShareMem und direkte Stringübergabe, oder die Verwendung von WideString.
WideString ist eine Kaspelung von String-APIs der OleAut32.dll (MSDN-Library durchsuchenSysAllocStringLen MSDN-Library durchsuchenSysStringLen MSDN-Library durchsuchenSysFreeString) und ist somit auch immer gleich und unabhängig vom Delphi-Speichermanager.

Schlecht ist es auch, wenn keine generischen Typen verwendet werden.
PChar und String können sich je nach Compiler (z.B. vor und nach ab Delphi 2009) verändern und schon verändert sich auch die Schnittstelle (PAnsiChar <> PWideChar | AnsiString <> UnicodeString), aber Schnittstellen müssen statisch/unveränderlich sein.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (19. Aug 2012 um 13:44 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:28 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz