erwin Posted July 11, 2007 Share Posted July 11, 2007 Hallo, hier war je schon die Frage zur Pluginerstellung unter .NET. Ich habe mich dann einige Weile mit der Erstellung eines Wrapper-Plugins beschäftigt, bis ich merkte dass man eine solche eigentlich gar nicht benötigt. Worum geht es? Nehmen wir ein Beispiel. Griga war so freundlich die API für die Verwaltung der Recorder-Programmierung zur Verfügung zu stellen. Obwohl DVBViewer GE kein COM kann, könnte mann jetzt trotzdem mit dieser API unter .NET komfortabel seine eigenen Erweiterungen erstellen, wenn nicht das Problem wäre, wie gehts dies unter C# z.B.? Besagtes API verwendet entsprechend parametrierte Sendmessage()-Aufrufe. Und vieles was man in einem Plugin sinnvolles tun kann, lässt sich über solche Sendmessage() realisieren. Sendmessage() kann man aber auch aus einer selbstständigen .NET-EXE heraus aufrufen nachdem man sich mit FindWindow() den DVBViewer-Fensterhandle beschafft hat. Problem: Beide EXE laufen in separierten Adressräumen, die Übergabe von Adressen von Strukturen an Sendmessage() führt zu verschiedenen Locationen in den beiden Adressräumen und damit nicht zum Erfolg. Man kann jedoch in den DVBViewer-Adressraum ein Memoryfenster hineinspiegeln, das man dann mit der zu übergebenen Struktur füllt, Sendmessage() mit diesem Memoryfenster ausführt und dann das gespiegelte Memory zurück in den .NET-Adressraum liest. Ich habe ein kleines .NET Demo-Projekt (MS Visual .NET) erstellt, welches genau dieses für die Recorder-Programmierung tut. DVBViewer GE aufrufen, dann "DVBViewer VCR DEMO.exe" und ausprobieren. Viel Spass! mfg erwin DVBViewer_VCR_DEMO.zip Quote Link to comment
klausb Posted July 18, 2007 Share Posted July 18, 2007 Hallo Erwin, sieht gut aus! Ich habe schon öfter überlegt mal endlich einen plugin zu schreiben, hatte aber nie richtig Lust meine Pascal-Kenntnisse aufzubessern. Mit C# sieht das ganze ja etwas anders aus (als Java-Entwickler auch kein Wunder). Hast du zum erwähnten Interface (SendMessage) noch mehr Info? Gruss, klaus. Quote Link to comment
Moses Posted July 18, 2007 Share Posted July 18, 2007 (edited) Für Java Entwikler gibt's noch eine Alternative mit recht leichtem Zugriff auf die COM Schnittstelle: JScript Damit lassen sich ziemlich einfach Anwendungen entwickeln, die mit dem DVBViewer über die COM Schnittstelle kommunizieren und das in Java Syntax. Die Klassenbibliothek ist nur manchmal etwas verwirrend und nicht wirklich mit der von Sun kompatibel SendMessage kommt übrigens aus der Win32 API. Damit kann man einer Anwendung beliebige Nachrichten schicken. Dazu sollte man recht viel Information finden. Ein paar der speziellen Nachriten, auf die der DVBViewer reagiert, gibt's glaub ich hier im SDK. Die Dokumentation erschien mir aber, als ich es ausprobiert hab, nicht so richtig vollständig... Edited July 18, 2007 by Moses Quote Link to comment
Griga Posted July 18, 2007 Share Posted July 18, 2007 Da es von allgemeinem Interesse zu sein scheint, poste ich hier die Interface-Infos, die Erwin erhalten hat, und das nachfolgende Frage/Antwort-Spiel. Das Interface müsste im Prinzip auch mit der Pro funktionieren. Vielleicht schaut Lars noch vorbei und checkt das durch. const WM_DVBVIEWER = $B2C2; //Use //Result := SendMessage(DVBViewer_Main_Window_Handle, // WM_DVBVIEWER, WParam, LParam); //Message_Constants sent as WParam MSG_VCR_GETCOUNT = $2300; //Message.Result = number of currently scheduled entries MSG_VCR_GETITEM = $2301; //LParam = pointer to a TVCRStruct_V2 (fill with zeros) //Set TVCRStruct_V2.ItemNr to the index of the desired entry //Message.Result = 0: Success, DVBViewer has filled the structure //Message.Result = -1: Failure MSG_VCR_SETITEM = $2302; //LParam = pointer to a TVCRStruct_V2 filled by the caller //Set TVCRStruct_V2.ItemNr to the index of the entry that shall be replaced //TVCRStruct_V2.ItemNr = -1: Append as new entry to the list //Message.Result = 0: Success, DVBViewer has stored the entry //Message.Result = -1: Failure MSG_VCR_DELETEITEM = $2303; //LParam = pointer to a TVCRStruct_V2 filled by the caller //Set TVCRStruct_V2.ItemNr to the index of the entry that shall be deleted //Message.Result = 0: Success, DVBViewer has deleted the entry //Message.Result = -1: Failure //TVCRStruct_V2.Days are encoded bitwise binMonday = $01; binTuesday = $02; binWednesday = $04; binThursday = $08; binFriday = $10; binSaturday = $20; binSunday = $40; binRepeat = $80; //GE auto-repeat flag binWorkDays = binMonday + binTuesday + binWednesday + binThursday + binFriday; binSatSun = binSaturday + binSunday; binAllDays = binWorkDays + binSatSun; type TString = array [0..255] of char; //null-terminated PString = ^TString; TShutdown = (sdNone, sdPowerOff, sdStandby, sdHibernate, sdClose, sdPlaylist, sdDVBViewerStandby); TTimerAction = (taRecord, taTune, taAudioPlugin, taVideoPlugin, taEPGUpdate); //communication record TVCRStruct_V2 = packed record //no alignment to dword boundaries! ItemNr: Integer; // Set by the caller Description: TString; Channel: TString; //channel ID StartTime: TDateTime; //without date, only fractional part! EndTime: TDateTime; //without date, only fractional part! //if EndTime < StartTime then StartTime is before and EndTime after midnight! //add 1 to the EndTime in this case Date: TDateTime; //date of the start time ShutDown: TShutdown; //Byte Unused: Byte; TimerAction: TTimerAction; //Byte Days: Byte; // 3.0 only 7 Bit - GE 8 Bit Enabled: Boolean; disableAV :Boolean; // 3.0 only - GE always false/ignore strReserved : TString; iReserved1 : Integer; iReserved2 : Integer; iReserved3 : Integer; end; PVCRStruct_V2 = ^TVCRStruct_V2; Noch eine Frage zur Gültigkeit/Lebensdauer von ItemNr. Bleibt diese während der Laufzeit des DVBV konstant oder verändert sich diese Kann sich schon durch das Hinzufügen / Ersetzen nur eines Eintrags ändern, weil die interne Liste (eine TList) nach jedem Vorgang aufsteigend nach der Anfangszeit neu sortiert wird. Die Sortierung ist zwingend notwendig, um vorausberechnen zu können, welche (sich überlappenden) Aufnahmen aufgrund der vorhandenen Hardware nicht durchführbar sind. Hier die verwendete Compare-Funktion: function GetStartTime(const Entry: TVCREntry): TDateTime; begin result := Entry.Date + Entry.StartTime; end; function GetEndTime(const Entry: TVCREntry): TDateTime; begin result := Entry.Date + Entry.EndTime; if Entry.EndTime < Entry.StartTime then result := result + 1; end; function CompareEntry(Item1,Item2: Pointer): Integer; begin result := CompareDateTime(GetStartTime(PVCREntry(Item1)^), GetStartTime(PVCREntry(Item2)^)); if result = 0 then result := CompareDateTime(GetEndTime(PVCREntry(Item1)^), GetEndTime(PVCREntry(Item2)^)); end; Also musst du entweder nach jedem Set die Liste neu holen, oder die Sortierung selbst herstellen. Sie ist wohlgemerkt nicht mit der dargestellten Sortierung identisch, die der Anwender selbst wählen kann! Locking, Synchronisation zwischen GET und SET u.s.ä. Die Synchronisation ist gewährleistet, solange alles, was passiert, aus der Abarbeitung der Message Queue resultiert. Im DVBViewer gibt es keine asynchronen Threads, die Timer-Einträge hinzufügen/ändern/löschen, und im Plugin würde ich mit solchen auch besser nicht operieren Ein Eintrag verschwindet aus der Anzeige - auch aus der TList mit neuer ItemNr.-Vergabe? Ja. Was nicht angezeigt wird, ist auch nicht in der Liste drin. Nur die Liste/Anzeige-Sortierung ist eventuell unterschiedlich. Du kannst davon ausgehen, dass die Liste, wenn sie das Plugin aufgrund eines Events in einer Schleife komplett mit mehreren SendMessage ausliest (Get), während des gesamten Handlings ein und es gleichen Events unverändert bleibt, es sei denn, du verwendest selbst in dem Ablauf Set. Änderungen können sich immer dann ergeben, wenn der DVBViewer zwischenzeitlich Gelegenheit hat, etwas aus der Message Queue abzuarbeiten, z.B. einen Timer-Event oder eine Benutzeraktion. Dein Event-Handling kann dadurch jedoch nicht unterbrochen werden, außer, wenn du darin sowas wie ProcessMessages verwendest. Das heißt, du müsstest bei jedem Event, während dessen Abarbeitung du auf die Liste zugreifst, sie komplett neu auslesen, um konsistent zu bleiben. Quote Link to comment
klausb Posted July 19, 2007 Share Posted July 19, 2007 Hallo Griga, ich frag einfach mal drauflos: Ist das Interface mit dem PluginIF identisch (habe noch nicht ins PluginIF reingeschaut, deswegen diese Frage). Und gibt es die Möglichkeit sich in Programmaktionen via Callback einzuhängen? Z.B. vor dem Umschalten wird mein Callback mit dem Sendername (oder ID) gerufen. Gruss, klaus. Quote Link to comment
erwin Posted July 26, 2007 Author Share Posted July 26, 2007 Das Interface müsste im Prinzip auch mit der Pro funktionieren. Vielleicht schaut Lars noch vorbei und checkt das durch. Folgende Unterschiede habe ich entdeckt: Das Setzen von DisableAV (über SendMessage()) scheint in der PRO nicht zu funktionieren. Beim Setzen des Datums ist es in der PRO immer um einen Tag höher als in der GE. mfg erwin Quote Link to comment
Lars_MQ Posted July 26, 2007 Share Posted July 26, 2007 Das funktioniert, ich nutze es ja selber im tvinfo plugin. Die deklarationen sind mit der GE identisch. Quote Link to comment
JMS Posted July 26, 2007 Share Posted July 26, 2007 Das Setzen von DisableAV (über SendMessage()) scheint in der PRO nicht zu funktionieren. Es gab da schon mal ein sehr eigenartiges Verhalten von Delphi bezüglich eines Boolean True Wertes. Wie überträgst Du True, als 1 oder -1? Nur so als Idee Jochen Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.