![]() |
Delphi-Version: 10 Seattle
QueryInterface und RefCount
Hallo Forum...
Ich versuche grad einen ca 900 Zeilen langen C++ Code nach Delphi zu übersetzen. Meinem ersten Gefühl nach ist der ganze folgende Code eigentlich nicht zwingend notwendig. Jedoch mag der Code insgesammt nicht funktionieren also versuche ich jetzt ob es damit vielleicht doch eine tiefere Bewandtnis hat. Dort ist Folgendes zu finden:
Code:
Mein Lösungsansatz sieht bisher so aus, jedoch weiß ich beim besten Willen nicht was der Code eigentlich tut...
class IUnknownImpl: IUnknown {
public: IUnknownImpl(GUID guid):_guid(guid) { }; HRESULT __stdcall QueryInterface(REFIID riid , void **ppObj) { if (riid == IID_IUnknown||riid == _guid) { *ppObj = this; AddRef() ; return S_OK; } *ppObj = NULL ; return E_NOINTERFACE ; } ULONG __stdcall AddRef () { return InterlockedIncrement(&m_nRefCount) ; } ULONG __stdcall Release () { long nRefCount=0; nRefCount=InterlockedDecrement(&m_nRefCount) ; if (nRefCount == 0) delete this; return nRefCount; } private: long m_nRefCount; //for managing the reference count GUID _guid; };
Delphi-Quellcode:
In Query Interface läuft er auf einen Fehler. Bin ich mit meinem Ansatz wenigstens dicht dran?
type
TIAVInterface = class(TInterfacedObject) function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; private FGUID: TGUID; public constructor create(GUID: TGUID); end; [..] constructor TIAVInterface.create(GUID: TGUID); begin inherited create(); FGUID:=GUID; end; function TIAVInterface.QueryInterface(const IID: TGUID; out Obj): HResult; begin if (IID = FGUID) then // OR Teil ergänzen begin Obj:=Self; // Operator ist auf diesen Operandentyp nicht anwendbar _AddRef; Result:=S_OK; end else begin Obj:=nil; Result:= E_NOINTERFACE; end; end; function TIAVInterface._AddRef: Integer; begin Result:=InterlockedIncrement(FRefCount); end; function TIAVInterface._Release: Integer; begin Result:=InterlockedDecrement(FRefCount); if Result = 0 then Self.Free; end; Toni |
AW: QueryInterface und RefCount
Wenn du von TInterfacedObject ableitest, dann ist die Referenzzählung bereits implementiert und du mußt das nicht selber einbauen, was IInterface als "Grundfunktion" benötigt.
Entweder du implementierst QueryInterface, _AddRef und _Release selber, oder du leitest von TInterfacedObject, TAggregatedObject, TInterfacedPersistent oder TComponent ab und erbst deren Verhaltensweisen. Bin mir nicht ganz sicher, aber wenn ich das mit der "GUID" so richtig sehe, dann von TObject ableiten und selber implementieren, oder vielleicht könnte es in Richtung TAggregatedObject gehen. :gruebel: Also selber implementieren und da dann
Delphi-Quellcode:
oder
IInterface(Obj) := Self;
Delphi-Quellcode:
oder irgendwas mit
IInterface(Obj) := Self as IInterface;
![]() und
Delphi-Quellcode:
IInterface(Obj) := nil;
|
AW: QueryInterface und RefCount
Liste der Anhänge anzeigen (Anzahl: 1)
Okay, also war mein erster Gedanke doch gar nicht so verkehrt...
Um ganz ehrlich zu sein. Was bei der Übersetzung dort von mir erwartet wird ist völliges Neuland für mich. Ich bin mir auch nicht sicher ob ich die Zusammenhänge überhaupt richtig verstanden hab. Könnte es helfen wenn ich den kompletten Code (nur die Interface Implementation) mal hier hoch lade? Es geht darum managed code aus einer DLL auszuführen. Der Hersteller hat dafür ein C++ Beispiel geschickt, dass, unter VS kompiliert, auch soweit kommt bis es die (nicht vorhandene) MS-SQL Datenbank nicht finden kann. An dieser Stelle will ich mit Delphi auf unsere vorhandene FirebirdDB verweisen. |
AW: QueryInterface und RefCount
Hatte oben noch bissl was geändert ... mit so "dynamischen" GUIDs kann Delphi standardmäßig halt nicht umgehen,
da dort normaler Weise alles über die statischen Interface-Tabellen in der RTTI läuft. Du könntest es vielleicht so machen, dass es intern einfach über den Zeiger vom IInterface läuft und leitest im QueryInterface dann bei der GUID es auf IInterface um, für die Berechnung des nötigen Interfacezeigers im QueryInterface. In QueryInterface muß/sollte aber unbedingt auch IInterface {00000000-0000-0000-C000-000000000046} implementiert sein, denn ich vermute, dass es sonst knallt, wenn jemand dieses Interface abfragt, welches Delphi fast überall als Grundinterface "verlangt". Bzw. implementiere es als ein "normales" Interface mit "statischer" GUID und leite es von der dynamischen GUID auf diese Statische um, falls überhaupt eine dynamische GUID nötig ist und man es nicht gleich Statisch implementieren kann. nil+E_NOINTERFACE wäre für IInterface vermutlich bissl ungeschickt. Für genauere Dinge hab ich im Moment aber auch erstmal keine Zeit. |
AW: QueryInterface und RefCount
Delphi-Quellcode:
Ich glaube aber nicht das dynamische GUID hier überhaupt nötig sind.
Pointer(Obj) := Self;
... Eine Ableitung von TInterfacedObject sollte für die Basisklasse genügen. Für die Kompatibilität zu COM-Objekten sollte IUnknown unterstütz, bzw. die anderen Interfaces sollten davon abgeleitet werden. |
AW: QueryInterface und RefCount
Zitat:
Delphi-Quellcode:
Ist euch zufällig die externe Exception E0434F4D bekannt? Das ist nämlich die Reaktion der DLL auf meine Klasse. Die Ergebnisse bei google sind leider recht vielfältig.
type
TIAVInterface = class(TInterfacedObject) function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; private FGUID: TGUID; public constructor create(GUID: TGUID); end; type ICientContextHolder = interface(IInterface) ['{00000000-0000-0000-0000-000000001112}'] end; PClientContextHolder = ^TClientContextHolder; TClientContextHolder = class(TInterfacedObject, ICientContextHolder) private FVin: LPWSTR; FVinKnown: BOOL; public constructor Create(); function GetSerialNumber(AInstance: PClientContextHolder): LPWSTR; virtual; stdcall; function GetLicencePlate(AInstance: PClientContextHolder): LPWSTR; virtual; stdcall; [..] end; Toni |
AW: QueryInterface und RefCount
Dieser "komische" Parameter ist vermuitlich das "implizite" SELF im Delphi.
Delphi-Quellcode:
Wie ist das mit dem Rückgabewert deiner Implmentationen?
type
ICientContextHolder = interface(IInterface) ['{00000000-0000-0000-0000-000000001112}'] function GetSerialNumber: LPWSTR; stdcall; function GetLicencePlate: LPWSTR; stdcall; end; TClientContextHolder = class(TInterfacedObject, ICientContextHolder) private FVin: LPWSTR; FVinKnown: BOOL; public constructor Create; function GetSerialNumber: LPWSTR; stdcall; function GetLicencePlate: LPWSTR; stdcall; [..] end; Also ich meine vorallem die Speicherverwaltung des PWideChar, damit das auch lange genug "nach" dem Aufruf der Methoden immernoch "lebt". Zitat:
|
AW: QueryInterface und RefCount
Delphi-Quellcode:
Ansonsten wie Himitsu bereits vorgeschlagen.
ICientContextHolder = interface(IUnknown)
|
AW: QueryInterface und RefCount
Zitat:
Zitat:
|
AW: QueryInterface und RefCount
IUnknown weist den Compiler an, das Interface kompatipel mit COM-Objekten zu erzeugen.
Hatte ich weiter oben schon geschrieben. Ob das hier einen Unterschied macht weis ich nicht. Aber da du eine COM-Exception bekommst, besteht eine gewisse Wahrscheinlichkeit... |
AW: QueryInterface und RefCount
Okay. Probiere ich aus...
|
AW: QueryInterface und RefCount
Okay, das Verhalten hat sich durch das Weglassen von AInstance verändert... Allerdings nicht zum Besseren. :?
Ich hatte die Implementation schon so weit, dass der DatabaseManager akzeptiert wurde und mir eine Art Callback gab in dem ich dann auf den ContextHolder zugreife (Zeile 168, Interface.hpp). Hier gab es die Methoden Signatur Exception. Wenn ich den AInstance Parameter weg lasse wird die Exception schon früher, beim Erzeugen des DatabaseManagers, geworfen. [Edit]Das Gleiche übrigens wenn ich virtual; weg lasse.[/Edit] Wenn ich das Interface implementiere wie von dir vorgeschlagen, allerdings mit dem "komischen Parameter", was mir auch durchaus logisch erscheint, bin ich wieder dort wo ich angefangen bin. Wieder Exception beim Zugriff auf den ContextHolder Zeile 168. Heisst das nun, dass die Implementation des DatabaseManagers bereits akzeptiert wurde und das Problem nur noch am ContextHolder liegt? Oder kann man das pauschal so nicht herleiten bevor man nicht Input und Output getestet hat? IUnknown und IInterface macht bis hier keinen Unterschied. Toni |
AW: QueryInterface und RefCount
Vieleicht hilft dir das weiter:
![]() |
AW: QueryInterface und RefCount
Mein Chef hat beschlossen, dass das alles zu lange dauert und ich muss nun zunächst ein anderes Projekt vorziehen.
Trotzdem möchte ich zukünfitgen "Probleminhabern" (:wink:) noch die vermeintliche (werde ich genau wissen wenn das Projekt abgeschlossen sein wird) Auflösung verraten. Sie basiert auf dem Vorschlag von Himitsu (Vielen Dank dafür) und wirft zumindest den Methoden-Signatur Fehler nicht mehr.
Delphi-Quellcode:
Gruß,
type
PClientContextHolder = ^TClientContextHolder; ICientContextHolder = interface(IUnknown) ['{00000000-0000-0000-0000-000000001112}'] function GetSerialNumber(): LPWSTR; stdcall; function GetLicencePlate(): LPWSTR; stdcall; [..] function GetVin(): LPWSTR; stdcall; procedure SetVin(AVin: LPWSTR); stdcall; end; TClientContextHolder = class(TInterfacedObject, ICientContextHolder) private FVin: LPWSTR; FVinKnown: BOOL; public constructor Create(); function GetSerialNumber(): LPWSTR; virtual; stdcall; function GetLicencePlate(): LPWSTR; virtual; stdcall; [..] function GetVin(): LPWSTR; virtual; stdcall; procedure SetVin(AVin: LPWSTR); virtual; stdcall; end; Toni |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:07 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