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

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
 
#2

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
 
#3

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
 
#4

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
Bbommel

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

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

  Alt 4. Apr 2012, 13:47
Hier mal ein neuer Zwischenstand, der mich aber nicht wirklich glücklicher macht:

Was das "safecall" angeht, ist das wohl eher eine Delphi-interne Geschichte, die besonders beim Import fremder ActiveX-DLLs nach Delphi relevant ist - ich suche aber ja den umgekehrten Fall. Das ist zumindest das, was ich zu dem Thema im Netz gefunden habe.

Um mal nicht direkt mit dem "großen" Visual Studio um mich zu schießen, habe ich auch mal eine 64-Bit-DLL erzeugt (und damit auch mal direkt gesehen, das wenigstens das funktioniert) und diese in ein VBScript eingebaut und aufgerufen. Ergebnis ist aber das selbe: Die Funktion, die ein Integer zurückgibt, kann ich problemlos aufrufen, aber den WideString bekomme ich nicht - der ganze Scripting-Host verabschiedet sich dann.

Nächster Ansatz: Anstelle den String direkt zurückzugeben, wird das Ergebnis in einer privaten Variable zwischengespeichert, die über die Property "LastResult" abgefragt werden kann. Funktioniert - so kommt der Text ohne Fehler sowohl bei VB.Net als auch im VBScript an. Aber das ist ja nicht das, was ich will! Es muss doch möglich sein, einen String als Rückgabewert zu haben! Ich habe selber schon (okay, in Delphi) fremde ActiveX-DLLs genutzt, die mir einen String zurückgeben. Und die DLL, die ich letztlich durch eine neue ablösen will, gibt auch die Ergebnisse fleißig als String zurück. Kann doch nicht sein, dass der aufrufende Programmierer jedes Mal dieses "LastResult" aufrufen muss. Irgendwas geht da schief... und ich finde keinen Ansatz...

Zur Verdeutlichung hier mal der Code, der "funktioniert":

Die Unit zur Implementierung:

Delphi-Quellcode:
unit teststr32_impl;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses
  ComObj, ActiveX, TestStr32_TLB, StdVcl;

type
  TStringOps = class(TAutoObject, IStringOps)
  private
    FLastResult: string;
  protected
    function CountStrLength(const aInStr: WideString): SYSINT; stdcall;
    function ReverseStr(const aInStr: WideString): SYSINT; stdcall;
    function Get_LastResult: WideString; safecall;
    procedure Set_LastResult(const Value: WideString); safecall;
  end;

implementation

uses ComServ;

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

function TStringOps.ReverseStr(const aInStr: WideString): SYSINT;
var i: integer;
    tempStr: string;
begin
  tempStr:='';
  for I := length(aInStr) downto 1 do
    tempStr:=tempStr+aInStr[i];
  FLastResult:=tempStr;
  Result:=0
end;

function TStringOps.Get_LastResult: WideString;
begin
  Result:=FLastResult;
end;

procedure TStringOps.Set_LastResult(const Value: WideString);
begin
  FLastResult:=Value;
end;

initialization
  TAutoObjectFactory.Create(ComServer, TStringOps, Class_StringOps,
    ciMultiInstance, tmApartment);
end.
Und der wesentliche Ausschnitt aus der _TBL.pas sieht so aus:

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): SYSINT; stdcall;
    function CountStrLength(const aInStr: WideString): SYSINT; stdcall;
    function Get_LastResult: WideString; safecall;
    procedure Set_LastResult(const Value: WideString); safecall;
    property LastResult: WideString read Get_LastResult write Set_LastResult;
  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): SYSINT; dispid 201;
    function CountStrLength(const aInStr: WideString): SYSINT; dispid 202;
    property LastResult: WideString dispid 203;
  end;
Und letztlich der Aufruf im Visual Studio:

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

        LabelResult.Text = testStr.ReverseStr(TextBoxInput.Text).ToString
        LabelResult2.Text = testStr.LastResult
    End Sub

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

        LabelResult.Text = testStr.CountStrLength(TextBoxInput.Text).ToString
    End Sub
End Class
Ich weiß ja nicht mal, ob ich irgendwas falsch mache oder ob es ein Bug in Delphi ist oder irgendwo an einer COM/Net-Zwischenschicht oder im Visual Studio (letzteres glaube ich nicht, da der gleiche Fehler ja auch im VBScript auftritt).

Wer auch immer Ideen hat, her damit. Werde wohl auch mal im Emba-Forum nachfragen, vielleicht weiß dort ja jemand etwas.

Bis denn
Bommel
  Mit Zitat antworten Zitat
shmia

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

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

  Alt 4. Apr 2012, 14:20
Im Anhang habe ich mal mein "ActiveXStarterKit" angehängt.
Programmiert mit Delphi 5.
Es enthält eine Anwendung mit Automatierungsschnittstelle sowie ein VBScript, mit dem die Anwendung angesteuert wird.
Delphi-Quellcode:
IApplication = interface(IDispatch)
    ['{1A8EFC07-D8CF-493C-B544-16080D82EBE6}']
    function Get_Version: WideString; safecall;
    procedure SendTextMessage(const text: WideString); safecall;
    function MethodeDieExceptionVerursacht: WideString; safecall;
    function Get_Caption: WideString; safecall;
    procedure Set_Caption(const Value: WideString); safecall;
    property Version: WideString read Get_Version;
    property Caption: WideString read Get_Caption write Set_Caption;
  end;
Falls ich mal Zeit finde, mache ich noch eine ActiveX DLL hinzu.
Angehängte Dateien
Dateityp: zip ActiveXStarterKit.zip (181,6 KB, 8x aufgerufen)
Andreas
  Mit Zitat antworten Zitat
Bbommel

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

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

  Alt 4. Apr 2012, 14:44
Vielen Dank für deine Unterstützung. So ganz ist mir aber noch nicht klar, was ich damit machen soll. In Delphi kann ich dein Projekt zwar öffnen und ausführen, aber was kann ich daraus lernen? Wenn ich die .vbs ausführe, bekomme ich einen Fehler ("ActiveX-Komponente kann kein Objekt erstellen"), was ich auch verstehen kann, denn ich habe ja nichts registriert, was VBS kennen könnte.

Sorry, wenn meine Nachfrage etwas "dumm" erscheint, aber nach bald zwei Tagen mit dem Murks dreht sich mir etwas der Kopf.

Du hast die ganzen .pas-Dateien aber manuell erstellt oder hast du dafür einen Assistenten von Delphi genutzt? Denn ich wunder mich immer noch über das "safecall", das (wie du ja oben siehst) Delphi bei mir nur bei den Getter/Setter benutzt und sonst nicht.

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 16:30 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