AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Delphi-ActiveX-DLL in VB.Net: Problem mit Strings
Thema durchsuchen
Ansicht
Themen-Optionen

Delphi-ActiveX-DLL in VB.Net: Problem mit Strings

Ein Thema von Bbommel · begonnen am 3. Apr 2012 · letzter Beitrag vom 5. Apr 2012
Antwort Antwort
Bbommel

Registriert seit: 27. Jun 2007
Ort: Köln
669 Beiträge
 
Delphi 12 Athens
 
#1

Delphi-ActiveX-DLL in VB.Net: Problem mit Strings

  Alt 3. Apr 2012, 14:51
Einen schönen Nachmittag in die Runde,

ich begebe mich gleich in drei Bereichen auf für mich neues Gebiet und stoße da vielleicht etwas an meine Grenzen: Testen von XE2, Entwicklung einer ActiveX-DLL und Arbeiten mit Visual Studio. Wobei ich letzteres vor allem nutzen wollte, um zu testen, ob das, was ich in Delphi an DLL erstellt habe, auch unter anderen Systemen funktioniert.

Das Ziel wird es letztlich sein, einem Kunden eine DLL zur Verfügung zu stellen, über die er von einem Server Daten in sein eigenes System importieren kann. Hier geht es aber jetzt erst einmal nur darum, ein paar ganz einfache Tests ans Laufen zu bekommen.

Ein Vorteil, statt einer "einfachen DLL" eine ActiveX-DLL zu nehmen, sei es unter anderem, dass man einfacher mit Strings arbeiten kann, so dachte ich. Doch genau daran scheitert es: Wenn ich aus VB.Net heraus eine Funktion aufrufe, die einen String zurückgibt, erhalte ich (in VB) eine Zugriffsverletzung.

Folgendes habe ich gemacht:

In Delphi ein neues Projekt erstellt, und zwar eine "ActiveX-DLL". Dort habe ich dann ein "Automatisierungsobjekt" hinzugefügt und diesem wiederum zwei Methoden verpasst. Die DLL "myteststr32.dll" exportiert dann die Typbibliothek "TestStr32" mit dem Interface "IStringOps" und dort den beiden Methoden "ReverseStr" und "CountStrLength".

"ReverseStr" soll einen String übergeben bekommen und diesen in umgekehrter Reihenfolge zurückgeben. "CountStrLength" soll einfach nur die Länge des Strings zurückgeben (spannend, oder? )

So sieht die Implementierung in Delphi aus:

Delphi-Quellcode:
unit teststr32_impl;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses
  ComObj, ActiveX, TestStr32_TLB, StdVcl;

type
  TStringOps = class(TAutoObject, IStringOps)
  protected
    function CountStrLength(const aInStr: WideString): SYSINT; stdcall;
    function ReverseStr(const aInStr: WideString): WideString; stdcall;
  end;

implementation

uses ComServ;

function TStringOps.CountStrLength(const aInStr: WideString): SYSINT;
begin
  Result:=Length(aInStr);
end;

function TStringOps.ReverseStr(const aInStr: WideString): WideString;

var i: integer;

begin
  Result:='';
  for I := length(aInStr) downto 1 do
    Result:=Result+aInStr[i];
end;

initialization
  TAutoObjectFactory.Create(ComServer, TStringOps, Class_StringOps,
    ciMultiInstance, tmApartment);
end.
Wenn ich die DLL, die beim Compilieren entsteht, registriere und dann in einem neuen Delphi-Projekt diese einbinde, dann klappt das auch alles ganz ausgezeichnet. Das Wichtige soll es aber sein, dass auch außerhalb der Delphi-Welt alles funktioniert.

Weil ich gerade eh ein Win8-Testsystem mit Visual Studio 2011 Beta hier habe, dachte ich mir, dass sich das doch gut für einen Test eignen würde.

Also: Neues WinForms-Projekt erstellt, zwei Buttons, ein Editfeld ("Textbox") und ein Label für die Ausgabe auf das Formular gezogen. Die DLL lässt sich hier mindestens so leicht wie in Delphi importieren (Projekt->Verweis hinzufügen) und kann dann im Code verwendet werden. Im Formular soll man nun in die Textbox einen beliebigen Text eingeben können. Bei dem Druck auf den einen Button soll angezeigt werden, wie lang der Text ist, beim anderen Button soll der umgedrehte Text ausgegeben werden. So sieht der Code aus:

Code:
Public Class Form1
    Private Sub ButtonReverse_Click(sender As Object, e As EventArgs) Handles ButtonReverse.Click
        Dim testStr As TestStr32.StringOps
        testStr = New TestStr32.StringOps

        LabelResult.Text = testStr.ReverseStr(TextBoxInput.Text)
    End Sub

    Private Sub ButtonLength_Click(sender As Object, e As EventArgs) Handles ButtonLength.Click
        Dim testStr As TestStr32.StringOps
        testStr = New TestStr32.StringOps

        LabelResult.Text = testStr.CountStrLength(TextBoxInput.Text).ToString
    End Sub
End Class
Funktioniert nur nicht. Also: ButtonLength_Click, also die Ausgabe, wie lang der String ist, klappt tadellos, aber die Ausgabe des umgedrehten Textes führt beim Aufruf der Funktion zu einer Zugriffsverletzung, also genau in der Zeile:
Code:
LabelResult.Text = testStr.ReverseStr(TextBoxInput.Text)
Ideen? Mache ich in VB irgendwas falsch oder in Delphi oder machen Strings hier generell wieder mal Probleme?

Hilfe!

Bis denn
Bommel
  Mit Zitat antworten Zitat
Iwo Asnet

Registriert seit: 11. Jun 2011
313 Beiträge
 
#2

AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings

  Alt 3. Apr 2012, 14:54
Versuch mal OleVariant als Typenbezeichnung anstatt Widestring.
  Mit Zitat antworten Zitat
Bbommel

Registriert seit: 27. Jun 2007
Ort: Köln
669 Beiträge
 
Delphi 12 Athens
 
#3

AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings

  Alt 3. Apr 2012, 15:06
Immerhin sieht die Fehlermeldung in VB jetzt anders aus:
Code:
Die Typensignatur der Methode ist nicht Interop-kompatibel.
(kommt an der selben Stelle wie vorher).

Auch wenn ich anstelle einer direkten Ausgabe ins Label zuerst mal versuche, das Ergebnis einer Variable vom Type "VariantType" oder "Object" zuzuweisen, bekomme ich diesen Fehler.

Hmmm....
  Mit Zitat antworten Zitat
Bbommel

Registriert seit: 27. Jun 2007
Ort: Köln
669 Beiträge
 
Delphi 12 Athens
 
#4

AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings

  Alt 3. Apr 2012, 16:09
Ich habe mir mal diese Liste angesehen und geschaut, welche Typen vielleicht noch in Frage kommen.

Nun habe ich mich für LPWSTR entschieden, was in der Delphi-Implementierung dann zu einem PWideChar wird. Ich habe gehofft, dass das funktioniert, weil es mich doch stark an eine "normale" DLL erinnert.

Tatsächlich war ich damit erfolgreich. Der Code in Delphi sieht nun so aus:

Delphi-Quellcode:
function TStringOps.ReverseStr(const aInStr: WideString): PWideChar;
var i: integer;
    tempStr: string;
begin
  tempStr:='';
  for I := length(aInStr) downto 1 do
    tempStr:=tempStr+aInStr[i];
  Result:=PWideChar(tempStr);
end;
Damit klappt es dann, die DLL, spezizell diese Methode, sowohl in einem anderen Delphi-Projekt wie auch im oben erwähnten VB.Net-Projekt einzubinden.

Jetzt bin ich zwar erst mal froh, dass es funktioniert, aber hat irgendwer noch eine Idee, was die Ursache für meine Probleme war? Liegt es daran, dass hier die Grenze zwischen COM- und .Net-Techniken überschritten wurde?

Danke fürs Lesen
Bommel
  Mit Zitat antworten Zitat
shmia

Registriert seit: 2. Mär 2004
5.508 Beiträge
 
Delphi 5 Professional
 
#5

AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings

  Alt 3. Apr 2012, 16:31
Also das "gefällt" mir gar nicht mit deinem PWideChar als Rückgabewert.
Das ist nicht sicher und auch nicht Scriptfähig.

Also, was du braucht ist ein sogenanntes Duales Interface.
Es zeichnet sich dadurch aus, dass es von IDispatch abgeleitet ist und man daher nur bestimmte (sichere) Datentypen verwenden darf.
Ausserdem werden Exceptions, die in deiner DLL entstehen automatisch aufgefangen und korrekt an den Aufrufer weitergeleitet.

Hier ein Beispiel.
Man erkennt
1.) ITest ist abgeleitet von IDispatch
2.) safecall Aufrufkonvention (wichtig für Exception Weiterleitung)
3.) Zusätzliches dispinterface - um den Zugriff über das IDispatch-Interface zu beschleunigen
Delphi-Quellcode:
// *********************************************************************//
// Schnittstelle: ITest
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {03D4B87D-FB7A-4632-831C-6318AE294C42}
// *********************************************************************//
  ITest = interface(IDispatch)
    ['{03D4B87D-FB7A-4632-831C-6318AE294C42}']
    function CountStringLength(const Value: WideString): Integer; safecall;
    function ReverseStr(const Value: WideString): WideString; safecall;
  end;

// *********************************************************************//
// DispIntf: ITestDisp
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {03D4B87D-FB7A-4632-831C-6318AE294C42}
// *********************************************************************//
  ITestDisp = dispinterface
    ['{03D4B87D-FB7A-4632-831C-6318AE294C42}']
    function CountStringLength(const Value: WideString): Integer; dispid 2;
    function ReverseStr(const Value: WideString): WideString; dispid 3;
  end;
Andreas
  Mit Zitat antworten Zitat
Bbommel

Registriert seit: 27. Jun 2007
Ort: Köln
669 Beiträge
 
Delphi 12 Athens
 
#6

AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings

  Alt 4. Apr 2012, 08:12
Hallo shmia,

Danke für deine Antwort - ich hatte mich in den Feierabend verabschiedet und komme erst jetzt zum weiteren Testen.

Glücklich macht mich das mit dem PWideChar auch noch nicht so richtig. Vor allem: wenn das schon nicht geht, wie soll das erst mit komplexeren Strukturen enden?

Das Problem ist: wenn ich alles richtig verstanden habe, dann habe ich bereits so ein duales Interface, abgeleitet von IDispatch. Der Code, den Delphi für meine testStr32_TLB.pas erzeugt, unterscheidet sich kaum von dem, den du gepostet hast. Als deutlichen Unterschied sehe ich nur den zwischen "stdcall" und "safecall":

(hier jetzt wieder WideString/BSTR als Rückgabetyp, nicht mehr PWideChar. In VB taucht wieder der Fehler auf)

Delphi-Quellcode:
// *********************************************************************//
// Interface: IStringOps
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {C97D8342-0B92-42AF-AB10-28A825B221FE}
// *********************************************************************//
  IStringOps = interface(IDispatch)
    ['{C97D8342-0B92-42AF-AB10-28A825B221FE}']
    function ReverseStr(const aInStr: WideString): WideString; stdcall;
    function CountStrLength(const aInStr: WideString): SYSINT; stdcall;
  end;

// *********************************************************************//
// DispIntf: IStringOpsDisp
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {C97D8342-0B92-42AF-AB10-28A825B221FE}
// *********************************************************************//
  IStringOpsDisp = dispinterface
    ['{C97D8342-0B92-42AF-AB10-28A825B221FE}']
    function ReverseStr(const aInStr: WideString): WideString; dispid 201;
    function CountStrLength(const aInStr: WideString): SYSINT; dispid 202;
  end;
Du hast zwar geschrieben, dass "safecall" vor allem eine Auswirkung für Exceptions hat, aber könnte das auch was mit den Strings zu tun haben? Wie sage ich Delphi in diesem Typbibliotheks-Editor denn, dass er safecall nutzen soll?

Bis denn
Bommel
  Mit Zitat antworten Zitat
Antwort Antwort


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 20:27 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz