Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   C++ WideString aus C++ DLL-Methode an Delphi-Host zurückgeben!? (https://www.delphipraxis.net/137067-widestring-aus-c-dll-methode-delphi-host-zurueckgeben.html)

MacGyver2k 13. Jul 2009 20:40


WideString aus C++ DLL-Methode an Delphi-Host zurückgeben!?
 
Hallo Leute,

ich habe ein Problem beim Rückgabetyp "WideString" aus einer C bzw. C++ DLL heraus.
Es besteht eine Delphi-Infrastruktur für Plugins, welche allerdings bisher ausschließlich auch mit Delphi-DLLs genutzt wurde.
Nun hab ich vor diese auch mit C/C++-DLLs zu füttern.
Geht so weit auch schonmal bei DLL-Methoden mit numerischen Rückgabe-Typen wie Integer und Bool und so weiter.
Bsp (C++):

Delphi-Quellcode:
bool DECLDIR EXTP_IsPlugIn( LPWSTR name )
{      
     return PlugIn.IsPlugIn( name );   
}
Sobal die in Delphi vorliegende Hostanwendung meine DLL lädt und die eben geschriebene Methode aufruft, geht das alles wunderbar so wie es sein soll.
Im Parameter "name" steht entsprechend die erwartete GUID als String - das konnte ich mit dem VS-Debugger prüfen.
Da ich nun hier und da schon gelesen habe, dass ein Delphi-WideString in C äquivalent mit einem LPWSTR ist, habe ich den Parametertyp auch so gewählt.
Das heißt, in diese Richtung funktioniert die Übergabe. Außerdem Kommt auch das BOOL-True in der Hostanwendung an, da die innere Methode bislang immer True zurückliefert.
Wenn ich nun aber eine Methode habe, die nach Anforderung im Delphi-Code einen WideString zurückliefern muss, so kommt absolut garnichts an - zum mindest sieht es aus wie ein leerer Sting "".
Hier mal noch eine Methode, die einen WideString zurückliefern soll (C++):

Delphi-Quellcode:
LPWSTR DECLDIR EXTP_GetPlugInDescription()
{
    return PlugIn.GetPlugInDescription();
}
Wie dem Code zu entnehmen ist, habe ich hier auch schon den Typ auf LPWSTR gesetzt. DECLDIR entsteht folgendermaßen (C++):
Delphi-Quellcode:
#define DECLDIR __declspec(dllexport)
Nun stellt sich mir die Frage, wie ich wohl einen String aus C/C++ in eine für Delphi akzeptable WideString-Konforme Variante überführe.
Hier nochmal die Deklaration der entsprechenden DLL-Methode in Delphi:

Delphi-Quellcode:
GetPlugInName = function : WideString; stdcall;
Ich würde mich tierisch freuen, wenn jemand hier einen Wink für mich hätte. Sonst muss ich mich nur weiterhin aufregen, dass der Entwickler dieser Pluginverwaltung unbedingt WideStrings nutzen muss, wo ich doch gelesen habe, dass man die grade in DLLs nicht unbedingt nehmen soll, sondern eher PChar, um eben solchen Problemen aus dem Weg zu gehen.

Vielen Dank an euch schonmal!!!
Grüße, MacGyver2k

Bernhard Geyer 14. Jul 2009 09:53

Re: WideString aus C++ DLL-Methode an Delphi-Host zurückgebe
 
Ich denke du wirst hier mit StringToOleStr arbeiten müssen um einen COM-String zu bekommen der nicht mehr unter der Speicherverwaltung von Delphi steht.

himitsu 14. Jul 2009 10:36

Re: WideString aus C++ DLL-Methode an Delphi-Host zurückgebe
 
Eigentlich braucht er in C nur den COM- / OLE-String verwalten
und Delphi macht dieses automatisch, bei Verwendung des WideString

MSDN-Library durchsuchenSysAllocStringLen
MSDN-Library durchsuchenSysReAllocStringLen
MSDN-Library durchsuchenSysFreeString
MSDN-Library durchsuchenSysStringLen

Delphi kapselt diese Befehle im WideString und dort wird alles nur an die WinAPI der oleaut32.dll weitergereicht.


Ich weiß jetzt nicht ob C dafür eventuell eine Klasse oder sowas hat, welches dieses auch schon kapselt, aber er braucht die Funktionen dann in C nur als LPWSTR bzw. BSTR deklarieren, deren Inhalt in C über die oben genannten Funktionen verwalten und in Delphi an gleicher Stelle der Funktionen alles einfach als WideString definieren.

etwa so:
Code:
bool DECLDIR EXTP_IsPlugIn( BSTR name )
Delphi-Quellcode:
function EXTP_IsPlugIn(const name: WideString): LongBool; stdcall;
// oder
function EXTP_IsPlugIn(var name: WideString): LongBool; stdcall;

[add]
war jetzt bool = ByteBool/Boolean und BOOL = LongBool ? :gruebel: wenn ja, dann natürlich anpassen.

Apollonius 14. Jul 2009 10:47

Re: WideString aus C++ DLL-Methode an Delphi-Host zurückgebe
 
Bei Strings ist doch const nicht gleich var, oder? :gruebel: Const sollte doch nur bewirken, dass keine Kopie angefertigt wird, und nicht die Übergabe beeinflussen.

Die WideString-Rückgabe dürfte übrigens nicht im EAX-Register erfolgen, sondern über einen versteckten Parameter, also ungefähr so:
Code:
void Foo(LPWSTR* result)

hathor 14. Jul 2009 11:07

Re: WideString aus C++ DLL-Methode an Delphi-Host zurückgebe
 
Probier doch einfach das:

Delphi-Quellcode:
GetPlugInName : array [0..xxxx] of WChar;

himitsu 14. Jul 2009 12:42

Re: WideString aus C++ DLL-Methode an Delphi-Host zurückgebe
 
Zitat:

Zitat von Apollonius
Bei Strings ist doch const nicht gleich var, oder? :gruebel:

jupp ... ich wußte nur grad nicht in welche Richtung der Wert übertragen werden sollte ... muß man sich dann nur das Passende (CONST, VAR, OUT oder nix) auswählen und dann verwenden.

Von Seiten der Schnittstelle ist aber CONST und VAR genau gleich,
nur daß bei CONST der Parameterinhalt nicht geändert wird (werden darf)
und bei VAR darf sich der Inhalt ändern kann.

@hathor: bezüglich der Speicherverwaltung könnte man da auch einfach auf PWideChar/LPWSTR umsteigen und Derjenige, welcher die Daten haben möchte übergibt dort einfach den nötigen Puffer (eventuell noch einen "BufferLen"-Parameter mit übergeben und auf der Füllenden Seite prüfen, ob der Puffer auch groß genug ist)

Apollonius 14. Jul 2009 12:53

Re: WideString aus C++ DLL-Methode an Delphi-Host zurückgebe
 
Zitat:

Zitat von himitsu
Von Seiten der Schnittstelle ist aber CONST und VAR genau gleich,
nur daß bei CONST der Parameterinhalt nicht geändert wird (werden darf)
und bei VAR darf sich der Inhalt ändern kann.

Sicher? Das sollte doch eigentlich nur bei Records so sein. Bei Strings ergibt Call-By-Const-Reference ja keinen Vorteil.

himitsu 14. Jul 2009 13:31

Re: WideString aus C++ DLL-Methode an Delphi-Host zurückgebe
 
für String/AnsiString/WideString/UnicodeString:

CONST, VAR und OUT ist alles call-by-reference

Ohne Angabe (von CONST VAR OUT) ist es zwar ebenfalls call-by-reference, allerdings wird da der Inhalt kopiert bzw. der Referenzzähler erhöht.

Bei einem WideString wird also ohne Angabe eine neue Kopie angelegt,
wärend VAR und CONST nur die Referenz übernehmen.


Ansonsten geben diese (VAR, CONST, OUT und nix) nur an, wie/ob der Parameterinhalt behandelt wird.

Apollonius 14. Jul 2009 13:37

Re: WideString aus C++ DLL-Methode an Delphi-Host zurückgebe
 
Das kann nicht sein, Himitsu. Ein var Widestring muss ein Zeiger auf einen PWideChar sein, sonst könntest du in der Routine nichts ändern. Const und fehlende Angabe resultieren hingegen in der Übergabe als PWideChar.

himitsu 14. Jul 2009 14:35

Re: WideString aus C++ DLL-Methode an Delphi-Host zurückgebe
 
ach menno, das Wetter ist wohl doch zu schlimm :|

OK, von der Übergabe ist es doch nicht gleich


also CONST und NIX ist gleich (call-by-const-reference),
sowie VAR und OUT (call-by-var-reference) :oops:

aber was die Behandlung der Inhalte angeht, bleibt es unverändert :angel2:

also dann so?
Delphi-Quellcode:
bool DECLDIR EXTP_IsPlugIn( BSTR name )
function EXTP_IsPlugIn(const name: WideString): Boolean; stdcall;

bool DECLDIR EXTP_IsPlugIn( BSTR* name )
function EXTP_IsPlugIn(var name: WideString): Boolean; stdcall;

MacGyver2k 14. Jul 2009 20:04

Re: WideString aus C++ DLL-Methode an Delphi-Host zurückgebe
 
Hi Leute,

schon mal vielen Dank für die zahlreiche Teilnahme an meinem Problem. Ich muss jetzt erstmal alle Posts durchlesen und dann handeln!
Aber wie das so im Überfliegen aussieht, ist bestimmt geiles dabei! Ich melde mich später wieder!

Grüße MacGyver2k

MacGyver2k 14. Jul 2009 21:43

Re: WideString aus C++ DLL-Methode an Delphi-Host zurückgebe
 
So nun hab ich alles gelesen und habe auch einiges davon ausprobiert. Leider funktioniert es immernoch nicht.
Zunächst muss ich leider sagen, dass die meisten Vorschläge auf Änderungen am Delphi Code hinauslaufen.
Ich habe leider nicht extra erwähnt, dass ich den Delphi Code zwar habe, ihn aber nicht abändern kann. Würde wohl auch mit bestehenden Plugins ins Gehege kommen.
Es geht auch wirklich ausschließlich daraum, wie ich den String aus C/C++ an Delphi zurückgebe. Denn Stringparameter von Delphi nach C kommen ohne probleme an.

Ich hab nun mal alles möglich eingebaut, was nur irgendwie sinnvoll scheint.
Dabei haben mich die Hinweise von himitsu am meisten inspiriert.
Außerdem habe ich auch wie Apollonius schrieb, mal das mit dem versteckten Parameter probiert.
Es kommt wie gesagt immernoch nichts raus.

Code:
DECLDIR LPCWSTR EXTP_GetPlugInName( LPCWSTR result )
{         
LPWSTR buffer = NULL;
int size = MultiByteToWideChar( CP_ACP, 0, "MyPluginName", -1, NULL, 0 );
buffer = (WCHAR*) malloc( sizeof( WCHAR ) * size );
MultiByteToWideChar( CP_ACP, 0, "MyPluginName", -1, buffer, size );
result = SysAllocStringLen( buffer, size );
return result;
//return PlugIn.GetPlugInName();
}
ich bin echt so langsam am verzweifeln :wall:

Apollonius 15. Jul 2009 17:15

Re: WideString aus C++ DLL-Methode an Delphi-Host zurückgebe
 
Ich sprach von einem Zeiger auf einen LPWSTR. :wink: Ohne die zusätzliche Inidrektion kann kein Wert zurück übertragen werden.

MacGyver2k 16. Jul 2009 00:33

Re: WideString aus C++ DLL-Methode an Delphi-Host zurückgebe
 
hi Apollonius,

danke für den Wink. Ich hab nun so wie ich es mir am plausibelsten denken konnte, das mit dem Zeiger auf LPWSTR probiert.
So wie ich es hier implementiert habe, funktioniert es leider nach wie vor nicht :( habe ich immernoch einen logik-fehler bei der ganzen Sache?

Code:
DECLDIR LPWSTR* EXTP_GetPlugInName( WCHAR** result )
{         
    int size = MultiByteToWideChar( CP_ACP, 0, "MyPluginName", -1, NULL, 0 );
    result = new WCHAR*;
    *result = new WCHAR[size];
    MultiByteToWideChar( CP_ACP, 0, "MyPluginName", -1, *result, size );
    return result;
}
LPWSTR entspricht dabei ja WCHAR*

Ich hoffe, dass ich wirklich noch irgendwo einen Hänger in meinem Kopf habe, den mir vieleicht irgendjemand aufzeigen kann.
Weiterhin Danke alle Helfer - auch im Voraus!

Apollonius 16. Jul 2009 12:32

Re: WideString aus C++ DLL-Methode an Delphi-Host zurückgebe
 
Dein Code aus #12 war schon fast richtig. Die Zuweisung in der vorletzten Zeile wird nur nicht an den Aufrufer durchgereicht, daher sollte das so aussehen:
Code:
DECLDIR void /*!*/ EXTP_GetPlugInName( LPCWSTR* /*!*/ result )
{         
LPWSTR buffer = NULL;
int size = MultiByteToWideChar( CP_ACP, 0, "MyPluginName", -1, NULL, 0 );
buffer = (WCHAR*) malloc( sizeof( WCHAR ) * size );
MultiByteToWideChar( CP_ACP, 0, "MyPluginName", -1, buffer, size );
*result /*!*/ = SysAllocStringLen( buffer, size );
free(buffer); //!
}
Der Rückgabetyp der Funktion sollte void sein. Außerdem solltest du buffer wieder freigeben.

MacGyver2k 18. Jul 2009 16:28

Re: WideString aus C++ DLL-Methode an Delphi-Host zurückgebe
 
Hi Apollonius,

ich krieg nen Knall - es geht!!! Du hast mir damit wirklich extremst geholfen! :cheers:
Das ganze öffnet mir nun den Weg, um über C++/CLI eine Bräsche zu .NET Code zu schlagen, und in meinen Plugins .NET Code einzusetzen.

Nochmals vielen Dank an Apollonius und natürlich auch alle anderen die hier ihre Zeit geopfert haben! THX!


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:42 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