Jump to content

DVBViewer Extensions in .NET (ohne COM)


Recommended Posts

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

Link to comment

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.

Link to comment

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 by Moses
Link to comment

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.

Link to comment

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.

Link to comment
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

Link to comment
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

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...