Problem mit Delphi-plugin nach C++Builder plugin uebersetzen
-
Hallo!
Ich mochte ein bereits geschriebenes Delphi-Plugin in C++Builder benutzen.
Habe es auch soweit so gut nach C++ uebersetzt, aber das Programm sturzt beim laden bzw. beim uebergen des Interfaces ab!
Ich bin schon seit mehreren Tagen am verzweifeln
Hab auch schon in vielen Forums nachgeschaut und den Code mehrmals neu geschrieben. Passt aber nichts.
In Delphi funktioniert es ohne Probleme.hier ist meine Export funktion:
extern "C" IUploadPlugin* __declspec(dllexport) __stdcall FlashRelease_UploadPlugin_CreateInterface() { TUploadPlugin *pP = new TUploadPlugin(); return (IUploadPlugin *)pP; }
in Delphi sieht es so aus:
function FlashRelease_UploadPlugin_CreateInterface: IUploadPlugin; stdcall; begin Result := TUploadPlugin.Create end; exports FlashRelease_UploadPlugin_CreateInterface;
Habs vergessen:
Hier ist das Programm: http://www.flashrelease.ru/files/flashrelease.exe
Und hier ist die Plugin-SDK zu dem Programm mit Beispielen in Delphi geschrieben: http://www.flashrelease.ru/files/sdk.zip
Hier ist die IUploadPlugin funktion von mir in C++ :
__interface IUploadPlugin; typedef System::DelphiInterface<IUploadPlugin> _di_IUploadPlugin; __interface IUploadPlugin : public System::IInterface { public: virtual __int64 __stdcall GetParamI(int Index) = 0 ; virtual System::WideString __stdcall GetParamS(int Index) = 0 ; virtual BOOL __stdcall Initialize(System::_di_IInterface Reserved, System::WideString &ExtraInfo, /* out */ HWND &MessageWindow) = 0 ; virtual BOOL __stdcall Finalize(System::_di_IInterface Reserved, System::WideString &ExtraInfo) = 0 ; virtual BOOL __stdcall UploadStream(_di_ISerialStream Stream, const System::WideString FileName, System::WideString &ExtraInfo, /* out */ System::WideString &URL) = 0 ; virtual void __stdcall ShowSettings(System::_di_IInterface Reserved) = 0 ; virtual void __stdcall ShowAboutBox(System::_di_IInterface Reserved) = 0 ; }; typedef _di_IUploadPlugin __stdcall (*TCreateInterface)(void);
in Delphi sieh Sie so aus:
type IUploadPlugin = interface function GetParamI(Index: Integer): Int64; stdcall; function GetParamS(Index: Integer): WideString; stdcall; function Initialize(Reserved: IInterface; var ExtraInfo: WideString; out MessageWindow: HWND): BOOL; stdcall; function Finalize(Reserved: IInterface; var ExtraInfo: WideString) : BOOL; stdcall; procedure ShowSettings(Reserved: IInterface); stdcall; procedure ShowAboutBox(Reserved: IInterface); stdcall; end;
-
WideString in Interfaces zu benutzen erscheint mir generell als keine gute Idee (wegen Speicherveraltung). Du müsstest wenigstens sicherstellen, dass DLL sowohl als auch Projekt die dynamische RTL benutzt. Damit ist auch gleich ausgeschlossen deine in C++ geschriebene DLL in Delphi Projekten zu nutzen. Es geht nicht mal die Nutzung in anderen Builder Versionen.
-
Morle schrieb:
WideString in Interfaces zu benutzen erscheint mir generell als keine gute Idee (wegen Speicherveraltung). Du müsstest wenigstens sicherstellen, dass DLL sowohl als auch Projekt die dynamische RTL benutzt. Damit ist auch gleich ausgeschlossen deine in C++ geschriebene DLL in Delphi Projekten zu nutzen. Es geht nicht mal die Nutzung in anderen Builder Versionen.
Doch, gerade bei WideString ist das alles kein Problem; WideString ist ein handlicher Wrapper für BSTR und hat überhaupt nichts mit der RTL zu tun; für Allokation und Freigabe sorgt Windows mit SysAllocString()/SysFreeString(). Was du sagst, wäre richtig, wenn er AnsiString oder UnicodeString verwenden würde.
giwig schrieb:
extern "C" IUploadPlugin* __declspec(dllexport) __stdcall FlashRelease_UploadPlugin_CreateInterface() { TUploadPlugin *pP = new TUploadPlugin(); return (IUploadPlugin *)pP; }
Zwei Dinge habe ich zu bemängeln: du solltest keinen rohen Zeiger zurückgeben, sondern einen DelphiInterface<>-Smart-Pointer, und du solltest keinen C-Cast verwenden, weil das alle Typsicherheit umgeht. Wenn du ohne Cast einen Fehler bekommst, hat das schon einen guten Grund.
Versuche zunächst mal das:extern "C" _di_IUploadPlugin __declspec(dllexport) __stdcall FlashRelease_UploadPlugin_CreateInterface() { TUploadPlugin* pp = new TUploadPlugin; return pp; }
Wenn das nicht funktioniert, dann zeige bitte mal die Klassendefinition von TUploadPlugin.
-
Versuche zunächst mal das:
extern "C" _di_IUploadPlugin __declspec(dllexport) __stdcall FlashRelease_UploadPlugin_CreateInterface() { TUploadPlugin* pp = new TUploadPlugin; return pp; }
Wenn das nicht funktioniert, dann zeige bitte mal die Klassendefinition von TUploadPlugin.
Klapt nicht. Das Progrmm sturzt immer noch beim laden der DLL ab.
Ich hab die implemintierung mit IUnknown, IInterface und was weis ich was es noch gibt versucht. Klapt alles nicht. Beim laden absturz.
In anderen Foren hab mehrere Plugins verglichen, die sowohl in Delphi, als auch in C++ weitergegeben werden. Verstehen tuh ich's immer noch nicht. Bei einem Plugin hab ich geseh. Es wird als Interface deklariert in Delphi und in CPP genau das gleiche, als eine einfache Klasse (AIMP SDK Plugin).Mit QueryInterface und AddRef usw... hab's auch schon versucht.
Die Klassendifinition von TUploadPlugin in Delphi sieht so aus:
Aber ich hab auch den QuellCode zu der Plugin-SDK hier oben gepostet http://www.flashrelease.ru/files/sdk.zip. Mit zwei Baispielen, die einwandfrei funktionieren.type TUploadPlugin = class(TInterfacedObject, IUploadPlugin) public function Initialize(Reserved: IInterface; var ExtraInfo: WideString; out MessageWindow: HWND): BOOL; stdcall; function Finalize(Reserved: IInterface; var ExtraInfo: WideString): BOOL; stdcall; function GetParamI(Index: Integer): Int64; stdcall; function GetParamS(Index: Integer): WideString; stdcall; function UploadStream(Stream: ISerialStream; const FileName: WideString; var ExtraInfo: WideString; out URL: WideString): BOOL; stdcall; procedure ShowSettings(Reserved: IInterface); stdcall; procedure ShowAboutBox(Reserved: IInterface); stdcall; end;
In meinem CPP-Header sieht es so aus:
class TUploadPlugin : public System::TInterfacedObject { typedef System::TInterfacedObject inherited; public: BOOL __stdcall Initialize(System::_di_IInterface Reserved, System::WideString &ExtraInfo, /* out */ HWND &MessageWindow); BOOL __stdcall Finalize(System::_di_IInterface Reserved, System::WideString &ExtraInfo); __int64 __stdcall GetParamI(int Index); System::WideString __stdcall GetParamS(int Index); BOOL __stdcall UploadStream(_di_ISerialStream Stream, const System::WideString FileName, System::WideString &ExtraInfo, /* out */ System::WideString &URL); void __stdcall ShowSettings(System::_di_IInterface Reserved); void __stdcall ShowAboutBox(System::_di_IInterface Reserved); public: /* TObject.Create */ inline __fastcall TUploadPlugin(void) : System::TInterfacedObject() { } /* TObject.Destroy */ inline __fastcall virtual ~TUploadPlugin(void) { } private: void *__IUploadPlugin; /* Uuploadapi::IUploadPlugin */ public: operator IUploadPlugin*(void) { return (Uuploadapi::IUploadPlugin*)&__IUploadPlugin; } };
-
giwig schrieb:
Klapt nicht. Das Progrmm sturzt immer noch beim laden der DLL ab.
Wenn TUploadPlugin in Delphi definiert wurde, sollte die von mir vorgeschlagene Funktion einen Übersetzungsfehler verursachen. Tut sie das bei dir nicht?
Ich erweitere meinen Vorschlag um das eigentlich Offensichtliche: befolge exakt meinen Ratschlag, und wenn dabei ein Compilerfehler auftritt, den du nicht verstehst, dann poste die Fehlermeldung.
-
audacia schrieb:
giwig schrieb:
Klapt nicht. Das Progrmm sturzt immer noch beim laden der DLL ab.
Wenn TUploadPlugin in Delphi definiert wurde, sollte die von mir vorgeschlagene Funktion einen Übersetzungsfehler verursachen. Tut sie das bei dir nicht?
Ich erweitere meinen Vorschlag um das eigentlich Offensichtliche: befolge exakt meinen Ratschlag, und wenn dabei ein Compilerfehler auftritt, den du nicht verstehst, dann poste die Fehlermeldung.
Habs versucht. Es wird ein Fehler ausgegeben.
[BCC32 Fehler] Main.cpp(193): E2285 Keine Übereinstimmung für 'operator _di_IUploadPlugin::= <ANOTHERINTF>(TUploadPlugin *)' gefunden Vollständiger Parser-Kontext Main.cpp(189): Analyse: _di_IUploadPlugin __stdcall FlashRelease_UploadPlugin_CreateInterface()
Also. Ich hab jetzt meinen Code in eine Datei gepack. Damit es einfacher wird, daran zu basteln. Und den poste ich jetzt hier, vielleicht entdeckt jemand einen Fehler, oder so.
//#include <vcl.h> #pragma hdrstop #pragma argsused #include <System.hpp> // Pascal unit #include <SysInit.hpp> // Pascal unit #include <Winapi.Windows.hpp> // Pascal unit #include <Winapi.Messages.hpp> // Pascal unit //-- user supplied ----------------------------------------------------------- //namespace Uuploadapi //{ //-- type declarations ------------------------------------------------------- __interface ISerialStream; typedef System::DelphiInterface<ISerialStream> _di_ISerialStream; __interface ISerialStream : public System::IInterface { public: virtual __int64 __stdcall Size(void) = 0 ; virtual __int64 __stdcall Position(void) = 0 ; virtual int __stdcall Read(void * Buffer, int Count) = 0 ; virtual void __stdcall Reset(void) = 0 ; }; __interface IUploadPlugin; typedef System::DelphiInterface<IUploadPlugin> _di_IUploadPlugin; __interface IUploadPlugin : public System::IInterface { public: virtual __int64 __stdcall GetParamI(int Index) = 0 ; virtual System::WideString __stdcall GetParamS(int Index) = 0 ; virtual BOOL __stdcall Initialize(System::_di_IInterface Reserved, System::WideString &ExtraInfo, /* out */ HWND &MessageWindow) = 0 ; virtual BOOL __stdcall Finalize(System::_di_IInterface Reserved, System::WideString &ExtraInfo) = 0 ; virtual BOOL __stdcall UploadStream(_di_ISerialStream Stream, const System::WideString FileName, System::WideString &ExtraInfo, /* out */ System::WideString &URL) = 0 ; virtual void __stdcall ShowSettings(System::_di_IInterface Reserved) = 0 ; virtual void __stdcall ShowAboutBox(System::_di_IInterface Reserved) = 0 ; }; typedef _di_IUploadPlugin __stdcall (*TCreateInterface)(void); //-- var, const, procedure --------------------------------------------------- #define EXPORT_FUNCTION_NAME L"FlashRelease_UploadPlugin_CreateInterface" #define PROGRESS_WINDOW_CLASS_NAME_GUID L"91DF0B7A66A941558AB4A190AFFE0725" #define PROGRESS_WINDOW_CLASS_NAME L"91DF0B7A66A941558AB4A190AFFE0725.UnicodeClass" static const System::Word WM_UPLOAD_TERMINATE = System::Word(0x8aab); static const System::Int8 PARAM_SUPPORT_IMAGES = System::Int8(0x0); static const System::Int8 PARAM_SUPPORT_AUDIO = System::Int8(0x1); static const System::Int8 PARAM_SUPPORT_VIDEO = System::Int8(0x2); static const System::Int8 PARAM_SUPPORT_FILES = System::Int8(0x3); static const System::Int8 PARAM_MAX_SIZE = System::Int8(0x4); static const System::Int8 PARAM_MAX_WIDTH = System::Int8(0x5); static const System::Int8 PARAM_MAX_HEIGHT = System::Int8(0x6); static const System::Int8 PARAM_SUPPORT_DESC = System::Int8(0x7); static const System::Int8 PARAM_SUPPORT_PASS = System::Int8(0x8); static const System::Int8 PARAM_SUPPORT_DELETE = System::Int8(0x9); static const System::Int8 PARAM_SUPPORT_PROXY = System::Int8(0xa); static const System::Int8 PARAM_NAME = System::Int8(0x0); static const System::Int8 PARAM_URL = System::Int8(0x1); static const System::Int8 PARAM_VERSION = System::Int8(0x2); static const System::Int8 PARAM_COPYRIGHT = System::Int8(0x3); static const System::Int8 PARAM_INFO = System::Int8(0x4); static const System::Int8 PARAM_AUTHOR = System::Int8(0x5); static const System::Int8 PARAM_SUPPORT_EXTS = System::Int8(0x6); //} /* namespace Uuploadapi */ //#if !defined(DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE) && !defined(NO_USING_NAMESPACE_UUPLOADAPI) //using namespace Uuploadapi; //#endif //-- user supplied ----------------------------------------------------------- //namespace Uuploadplugin //{ //-- type declarations ------------------------------------------------------- class DELPHICLASS TUploadPlugin; //class PASCALIMPLEMENTATION TUploadPlugin : public System::TInterfacedObject class TUploadPlugin : public System::TInterfacedObject { typedef System::TInterfacedObject inherited; public: BOOL __stdcall Initialize(System::_di_IInterface Reserved, System::WideString &ExtraInfo, /* out */ HWND &MessageWindow); BOOL __stdcall Finalize(System::_di_IInterface Reserved, System::WideString &ExtraInfo); __int64 __stdcall GetParamI(int Index); System::WideString __stdcall GetParamS(int Index); //BOOL __stdcall UploadStream(Uuploadapi::_di_ISerialStream Stream, const System::WideString FileName, System::WideString &ExtraInfo, /* out */ System::WideString &URL); BOOL __stdcall UploadStream(_di_ISerialStream Stream, const System::WideString FileName, System::WideString &ExtraInfo, /* out */ System::WideString &URL); void __stdcall ShowSettings(System::_di_IInterface Reserved); void __stdcall ShowAboutBox(System::_di_IInterface Reserved); public: /* TObject.Create */ inline __fastcall TUploadPlugin(void) : System::TInterfacedObject() { } /* TObject.Destroy */ inline __fastcall virtual ~TUploadPlugin(void) { } private: void *__IUploadPlugin; /* Uuploadapi::IUploadPlugin */ public: //operator Uuploadapi::IUploadPlugin*(void) { return (Uuploadapi::IUploadPlugin*)&__IUploadPlugin; } operator IUploadPlugin*(void) { return (IUploadPlugin*)&__IUploadPlugin; } }; //-- var, const, procedure --------------------------------------------------- //} /* namespace Uuploadplugin */ //#if !defined(DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE) && !defined(NO_USING_NAMESPACE_UUPLOADPLUGIN) //using namespace Uuploadplugin; //#endif extern "C" int _libmain(unsigned long reason) { return 1; } BOOL __stdcall TUploadPlugin::Initialize(System::_di_IInterface Reserved, System::WideString &ExtraInfo,HWND &MessageWindow) { MessageBoxW(0,L"::Initialize()",L"DLL Run",MB_OK); return 0; } BOOL __stdcall TUploadPlugin::Finalize(System::_di_IInterface Reserved, System::WideString &ExtraInfo) { return 0; } __int64 __stdcall TUploadPlugin::GetParamI(int Index) { switch(Index) { case PARAM_SUPPORT_IMAGES : return 1; case PARAM_MAX_SIZE : return 5*1024; case PARAM_SUPPORT_PROXY : return 0; default: return 0; } } System::WideString __stdcall TUploadPlugin::GetParamS(int Index) { switch(Index) { case PARAM_SUPPORT_EXTS : return L".gif;.jpg;.png;.bmp:"; case PARAM_NAME : return L" "; case PARAM_VERSION : return L" "; case PARAM_COPYRIGHT : return L" "; case PARAM_INFO : return L" "; case PARAM_AUTHOR : return L" "; case PARAM_URL : return L" "; default : return L" "; } } BOOL __stdcall TUploadPlugin::UploadStream(_di_ISerialStream Stream, const System::WideString FileName, System::WideString &ExtraInfo, System::WideString &URL) { return true; } void __stdcall TUploadPlugin::ShowSettings(System::_di_IInterface Reserved) { } void __stdcall TUploadPlugin::ShowAboutBox(System::_di_IInterface Reserved) { } extern "C" _di_IUploadPlugin __declspec(dllexport) __stdcall FlashRelease_UploadPlugin_CreateInterface() { TUploadPlugin* pp = new TUploadPlugin; MessageBoxW(0,L"FlashRelease_UploadPlugin_CreateInterface()",L"DLL",MB_OK); // Hier tritt ein Compiler-Fehler auf. //return pp; // So funktioniert es, gibt jedoch beim Laden der DLL eine Exception EAccessViolation beio Adresse so und so aus. // return (IUploadPlugin *)pp; }
So wie "Audacia" schon bereits sagte. Ich Schatze dass der Fehler irgendwo hier (bei der uebergabe der Adresse) liegt.
// Hier tritt ein Compiler-Fehler auf. //return pp; // So funktioniert es, gibt jedoch beim Laden der DLL eine Exception EAccessViolation beio Adresse so und so aus. // return (IUploadPlugin *)pp;
Ich hab schon so viele moeglichkeiten mit den Pointern ausprobiert, dass ich schon am verzweifeln bin.
Es kann doch nicht schwehr sein, einen einfachen PLUGIN mit zwei Klassen nach CPP zu portieren, oder hatt es etwas vielleicht mit dem Delphi-Stack irgendwie zu tun.
-
giwig schrieb:
Habs versucht. Es wird ein Fehler ausgegeben.
[BCC32 Fehler] Main.cpp(193): E2285 Keine Übereinstimmung für 'operator _di_IUploadPlugin::= <ANOTHERINTF>(TUploadPlugin *)' gefunden Vollständiger Parser-Kontext Main.cpp(189): Analyse: _di_IUploadPlugin __stdcall FlashRelease_UploadPlugin_CreateInterface()
Dachte ich mir doch. Es hat schon einen Sinn, wenn ich sage, du sollst keinen C-Cast verwenden; da bringt es natürlich nichts, wenn du den stillschweigend wieder einführst, meinst du nicht?
Wenn du dir die C++-Übersetzung der Delphi-Klasse genauer anschaust, sollte dir der richtige Weg, um einen IUploadPlugin-Zeiger zu bekommen, direkt ins Auge springen:
class TUploadPlugin : public System::TInterfacedObject { ... public: operator IUploadPlugin*(void) { return (Uuploadapi::IUploadPlugin*)&__IUploadPlugin; } };
Das ist ein impliziter Konvertierungsoperator. D.h., folgendes funktioniert:
TUploadPlugin* p; _di_IUploadPlugin i = *p; // Dereferenzierung -> implizite Konvertierung
Oder eben so:
extern "C" _di_IUploadPlugin __declspec(dllexport) __stdcall FlashRelease_UploadPlugin_CreateInterface() { TUploadPlugin* pp = new TUploadPlugin; return *pp; // // Dereferenzierung -> implizite Konvertierung }
Alles ganz ohne explizite Casts und wunderbar typsicher.
Was lernen wir daraus? C-Casts sind in C++ immer der falsche Weg.
-
operator IUploadPlugin*(void) { return (Uuploadapi::IUploadPlugin*)&__IUploadPlugin; }
Diese Zeile hat mich schon etwas irritiert.
Werde es gleich testen
extern "C" _di_IUploadPlugin __declspec(dllexport) __stdcall FlashRelease_UploadPlugin_CreateInterface() { TUploadPlugin* pp = new TUploadPlugin; return *pp; // // Dereferenzierung -> implizite Konvertierung }
Alles ganz ohne explizite Casts und wunderbar typsicher.
Was lernen wir daraus? C-Casts sind in C++ immer der falsche Weg.
Danke! Werde mich dann melden