![]() |
Delphi-ActiveX-DLL in VB.Net: Problem mit Strings
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? :-D) So sieht die Implementierung in Delphi aus:
Delphi-Quellcode:
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.
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. 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:
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:
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
Code:
Ideen? Mache ich in VB irgendwas falsch oder in Delphi oder machen Strings hier generell wieder mal Probleme?
LabelResult.Text = testStr.ReverseStr(TextBoxInput.Text)
Hilfe! :) Bis denn Bommel |
AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings
Versuch mal OleVariant als Typenbezeichnung anstatt Widestring.
|
AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings
Immerhin sieht die Fehlermeldung in VB jetzt anders aus:
Code:
(kommt an der selben Stelle wie vorher).
Die Typensignatur der Methode ist nicht Interop-kompatibel.
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.... |
AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings
Ich habe mir mal
![]() 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:
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.
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; 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? :glaskugel: Danke fürs Lesen Bommel |
AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings
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; |
AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings
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:
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?
// *********************************************************************//
// 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; Bis denn Bommel |
AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings
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! :wall: 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:
Und der wesentliche Ausschnitt aus der _TBL.pas sieht so aus:
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.
Delphi-Quellcode:
Und letztlich der Aufruf im Visual Studio:
// *********************************************************************//
// 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;
Code:
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).
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 Wer auch immer Ideen hat, her damit. Werde wohl auch mal im Emba-Forum nachfragen, vielleicht weiß dort ja jemand etwas. Bis denn Bommel |
AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings
Liste der Anhänge anzeigen (Anzahl: 1)
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:
Falls ich mal Zeit finde, mache ich noch eine ActiveX DLL hinzu.
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; |
AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings
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 |
AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings
Zitat:
1.) beiliegende EXE starten (EXE registriert sich selber) und danach Script starten sollte funktionieren Damit wäre bewiesen, dass der Windows Scripting Host mit VBScript auf deinem Rechner ohne Problem läuft. Es wird auch bewiesen, dass Exceptions zurück an das Script geliefert werden. 2.) Projekt mit deinem Compiler übersetzen und Test von 1.) wiederholen damit wäre bewiesen, dass deine Delphi Umgebung prinzipiell funktionierende ActiveX-Anwendungen erzeugen kann 3.) Anstelle der EXE muss nun im nächsten Test eine ActiveX DLL treten. Diese wird ebenfalls mit einem (neu zu erstellenden) VBScript getestet 4.) Einbinden in .NET / C# und testen |
AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings
Mal ganz vorab: ich habe das Gefühl, das bei diesem ganzen Kram auch die Betriebssystem-Version nicht ganz unwichtig ist. Ich habe Win7, 64-Bit, Delphi 2009, und als zweites Testsystem (wo auch Visual Studio 2011 Beta und die Testversion von XE2 drauf laufen) Win8 Consumer Preview, ebenfalls 64-Bit.
Hm. Also der Reihe nach: 1.: Versuch, die exe direkt auszuführen Die exe funktioniert leider nicht. Windows meldet sich direkt damit, dass das Programm nicht ausgeführt werden kann. Danach erscheint noch folgende Fehlermeldung: --------------------------- Anwendungsfehler --------------------------- Exception EOleSysError in Modul ActiveXStarterKit.exe bei 000453A5. Fehler beim Zugriff auf OLE-Registrierung. --------------------------- 2.: Neukompilieren der exe mit meinem Delphi 2009 Wenn ich das Projekt in mein Delphi 2009 (also das in meiner Produktiv-Umgebung) lade und compiliere, dann kann ich die exe nachher problemlos starten. Allerdings funktioniert das .vbs noch immer nicht und liefert mir die Meldung: --------------------------- Windows Script Host --------------------------- Skript: D:\Eigene Dateien\Borland Studio-Projekte\delphi-praxis\activeXstarterKit\TestScript.vbs Zeile: 3 Zeichen: 10 Fehler: ActiveX-Komponenten kann kein Objekt erstellen: 'ActiveXStarterKit.Application_' Code: 800A01AD Quelle: Laufzeitfehler in Microsoft VBScript --------------------------- 3.: Compilieren als 64-Bit-Exe mit XE2 Um auszuschließen, dass es jetzt irgendwie an 32/64-Bit-Problemen scheitert, habe ich das Ganze noch mal unter XE2 als 64-Bit compiliert, aber das brachte auch keine Besserung. exe läuft, aber vbs sieht sie nicht. Du meintest, die Bibliothek würde sich selbst registrieren - wo tut sie das denn? Nur, um wenigstens das mal zu verstehen. Ich glaube aber eigentlich nicht, dass bei mir der Scripting Host defekt ist. Das Problem tritt ja sowohl bei meinem normalen Win7 wie auch bei dem recht frischen Win8-Testsystem auf. Ich versuche mir mal, ein olles XP zu basteln, vielleicht kommen wir des Rätsels Lösung dann ja näher... :) Bis denn Bommel |
AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings
Zitat:
Du musst die Testanwendung einmal mit vollen Admin-Rechten starten. (rechter Mausklick -> Als Administrator starten) Dabei verankert sie sich in der Registry unter HKEY_LOCAL_Machine. Falls du die Registrierung wieder loswerden willst das Programm mit dem Parameter /unregserver starten. Zitat:
Mit dem (Kommandozeilen-)Parameter /regserver führt die Anwendung nur die Registrierung durch und beendet sich sogleich. DLL und OCX müssen dagegen von Aussen mit dem Tool RegSvr32.exe (bzw. RegSvr64) registriert werden. |
AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings
Hm, ich hatte gedacht, das mit den Admin-Rechten hätte ich schon getestet gehabt... hmpf. Zu viele Tests. :)
Also noch mal: 1.: Test von deiner exe Also, ich habe eine Eingabeaufforderung mit Admin-Rechten gestartet und von dieser aus sowohl deine exe gestartet wie auch die vbs-Datei. Scheint zu funktionieren: Ich erhalte zunächst ein Popup... --------------------------- Version: 1.0 beta Programm:ActiveX Starter Kit --------------------------- ...und im Fenster des Programms erscheinen zwei Zeilen mit einem Gruß des Scripts. Nur am Ende des Scripts erhalte ich eine Fehlermeldung, schätze aber mal, dass die jetzt nichts mit unserem Problem zu tun hat: --------------------------- Windows Script Host --------------------------- Skript: D:\Eigene Dateien\Borland Studio-Projekte\delphi-praxis\activeXstarterKit\TestScript.vbs Zeile: 11 Zeichen: 1 Fehler: IApplication.GetPath: Invalid Argument Code: 80040096 Quelle: ActiveXStarterKit.Application_ --------------------------- 2.: Compilieren mit D2009 Funktioniert dann jetzt genauso wie 1). Cool. Vielen Dank schon mal. Das ist immerhin das erste Mal heute, dass ich das Gefühl habe, einen Schritt weiter gekommen zu sein. Dann kann ich ja wenigstens mal mit ein bisschen Optimismus in den Feierabend gehen... :) Schönen Abend noch Bommel |
AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings
Hiho,
hier mal die aktuellen Fortschritte... Zunächst mal der Link zum selben Thema im Emba-Forum: ![]() Um mal die Ergebnisse von da zusammenzufassen: Dort gab es noch einen Hinweis, dass ich die Funktionen anders deklarieren muss in der IDL-Datei, aus der dann ja letztlich die Typbibliothek entsteht. Es soll nicht der String als Rückgabewert der Funktion genommen werden, sondern HRESULT und dann der eigentliche Rückgabewert in einem out-Parameter erscheinen. Das sieht dann in der ridl-Datei so aus:
Code:
Witzigerweise entsteht dann in den .pas-Dateien von Delphi genau der Code mit einem "safecall", auf den shmia die ganze Zeit hinaus wollte:
interface IStringOps: IDispatch
{ [id(0x000000C9)] HRESULT _stdcall ReverseStr([in] BSTR aInStr, [out, retval] BSTR oResult); }; So sieht es in der TLB.pas aus:
Delphi-Quellcode:
Und so in der Implentierung:
// *********************************************************************//
// Interface: IStringOps // Flags: (4416) Dual OleAutomation Dispatchable // GUID: {8A734903-13FF-46BF-BC02-4E596CBE514F} // *********************************************************************// IStringOps = interface(IDispatch) ['{8A734903-13FF-46BF-BC02-4E596CBE514F}'] function ReverseStr(const aInStr: WideString): WideString; safecall; end; // *********************************************************************// // DispIntf: IStringOpsDisp // Flags: (4416) Dual OleAutomation Dispatchable // GUID: {8A734903-13FF-46BF-BC02-4E596CBE514F} // *********************************************************************// IStringOpsDisp = dispinterface ['{8A734903-13FF-46BF-BC02-4E596CBE514F}'] function ReverseStr(const aInStr: WideString): WideString; dispid 201; end;
Delphi-Quellcode:
Wie man sieht, kommt das "HRESULT" hier dann gar nicht mehr vor, stattdessen taucht aber wie gesagt dann plötzlich ein "safecall" auf.
type
TStringOps = class(TAutoObject, IStringOps) protected function ReverseStr(const aInStr: WideString): WideString; safecall; end; implementation uses ComServ; function TStringOps.ReverseStr(const aInStr: WideString): WideString; var i: integer; tempStr: string; begin tempStr:=''; for I := length(aInStr) downto 1 do tempStr:=tempStr+aInStr[i]; Result:=tempStr; end; Interessant ist jetzt, dass ich die Funktion in VB.Net nutzen kann, wenn ich sie mit später Bindung aufrufe:
Code:
Das ist ja schon mal fein. Wenn ich die Funktion allerdings über "Verweis hinzufügen..." schon zur Designzeit dem Projekt hinzufügen möchte, dann knallt das ganze Visual Studio - obwohl das vorher, mit den vorigen Tests, wenigstens immer funktioniert hat.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim teststr As Object teststr = CreateObject("TestStr32Out.StringOps") MessageBox.Show(teststr.ReverseStr("Hallo")) End Sub Auch im VBscript funktioniert es nicht:
Code:
...führt dazu, dass der Scripting Host sich verabschiedet.
dim mystr
set mystr = CreateObject("TestStr32Out.StringOps") wscript.echo "Hallo = "+mystr.ReverseStr("Hallo") Also - Fortschritte ja, aber auch nur so irgendwie ein bisschen. :) Bin gespannt auf weitere Ideen... Bis denn Bommel |
AW: Delphi-ActiveX-DLL in VB.Net: Problem mit Strings
Es scheint im Moment, als hätte ich die Lösung gefunden. Wenn ich aus dem out-Parameter einen "BSTR *" mache anstelle eines "BSTR" (was auch zum Hinweis des Delphi-Assistenten passt, man möge doch bei einem out-Parameter bitte einen Zeigertyp verwenden), dann funktioniert alles in VB.Net und in VBScript. :dancer:
Die .pas-Dateien sind im Vergleich zum vorigen Post unverändert. Die ridl-Datei sieht dann so aus:
Code:
Ich hoffe, das war es dann erstmal. Vielen Dank an shmia für die Unterstützung.
interface IStringOps: IDispatch
{ [id(0x000000C9)] HRESULT _stdcall ReverseStr([in] BSTR aInStr, [out, retval] BSTR* oResult); }; Bis denn Bommel |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:19 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