Seite 1 von 1
Plugin in FreePascal / Lazarus
Verfasst: 10.01.2012, 18:45
von Ingo
Hi Christian!
Ich versuche gerade, ein Programmplugin in Lazarus zu schreiben. Leider bekomme ich (für mich) undursichtige Fehler, solbald ich die Szenenbibliothek öffne (Bibliothek öffnet, ich wähle eine Szene und klicke Ok, Fehler)

. Ich sende nur MSG_OPENLIBRARY, die DLL_SendMessage ist leer. PC_DIMMER sagt entweder "Fehlerbehaftete DLL" (sehr hilfreich) oder "Zugriffsverletzung bla bla bla" (kennst du ja sicher

) ... Hast du dich schon mal mit Lazarus beschäftigt? Ich habe mal dein Beispielplugin in Lazarus importiert, das scheitert aber leider genauso beim Aufruf.
Mein Problem ist dass ich hier drüben kein Borland-Delphi habe, was ich sonst benutzt habe.
Hast du irgend eine Idee, wie ich mir helfen könnte? Könntest du vielleicht eine etwas detailiertere Fehlerbehandlung/-ausgabe auf DLL-Aufrufe anwenden? Das könnte mir eventuell schon helfen.
Viele Grüße,
Ingo
Edit: Ich habe ein bisschen
gelesen und habe die Hoffnung, dass es funktioniert wenn du mir das Application.Handle übergibst. Geht das irgendwie? Können wir das ausprobieren? Ich weiß sonst nicht weiter. Das ist ein ziemlich blödes Problem, zudem ja Debuggen schwierig wird.
Re: Plugin in FreePascal / Lazarus
Verfasst: 11.01.2012, 08:25
von Christian
Hi Ingo,
werden denn die einzelnen Funktionen wirklich als "stdcall" von deinem Plugin exportiert? Möglicherweise ist das schon das Problem. Wenn dem so ist, könnte es noch an irgendwelchen inkompatiblen String-Einstellungen liegen, da auch bei Aufruf von "MSG_OPENLIBRARY" ein String an das Hauptprogramm übergeben wird, damit man beim Öffnen der Bibliothek gleich eine bestimmte Szene per ID-String markieren lassen kann.
Leider habe ich keine Erfahrung mit Lazarus. Wenn es gar nicht geht, könntest Du von der Borland/CodeGear/Embarcadero-Seite die Seriennummer für Borland Delphi 7 Personal herunterladen und diese Version zum Kompilieren verwenden. Das Setup zu D7 Personal geistert im Internet auch noch rum. Ist völlig legal und man hat keine Kompatibilitätsprobleme.
Eine bessere Fehlerauswertung hatte ich mal probiert, allerdings war das bei Plugins nicht ganz so einfach. Da kann ich glaube ich kurzfristig nicht viel machen.
bis dann,
Christian
Re: Plugin in FreePascal / Lazarus
Verfasst: 11.01.2012, 19:44
von Ingo
Hi!
admin hat geschrieben:werden denn die einzelnen Funktionen wirklich als "stdcall" von deinem Plugin exportiert? Möglicherweise ist das schon das Problem. Wenn dem so ist, könnte es noch an irgendwelchen inkompatiblen String-Einstellungen liegen, da auch bei Aufruf von "MSG_OPENLIBRARY" ein String an das Hauptprogramm übergeben wird, damit man beim Öffnen der Bibliothek gleich eine bestimmte Szene per ID-String markieren lassen kann.
Überall steht stdcall dahinter, und die Bibliothek wird ja geöffnet, nur kommt nach dem Auswählen der Scene und Drücken des Buttons "Ok" diese unglaublich aufklärende Fehlermeldung. Beim Drücken von Abbrechen schließt der Dialog normal und es passiert nichts. Ich habe die Funktionalität auch schon mit einem eigenen Testprogramm geprüft, welches einen Dialog anzeigt und anschließend die MSG_LIBRARYVALUE - Message sendet. Das klappt einwandfrei.
Könntest du mir vielleicht mal den Code zeigen, wo du die Bibliothek öffnest und danach die Scenen-ID und den Namen zurücksendest? Ist da irgendwas besonderes?
Danke für deine Bemühungen!
Viele Grüße,
Ingo
Re: Plugin in FreePascal / Lazarus
Verfasst: 11.01.2012, 23:12
von Christian
Hi Ingo,
hier ist der gesamte Code für die Callback-Funktion:
Code: Alles auswählen
procedure CallbackMessage(MSG:Byte; Data1, Data2:Variant);stdcall;
var
i,j:integer;
// mididata:Variant;
SzenenData:PTreeData;
begin
with mainform do
begin
if not startingup then
case MSG of
MSG_RECORDSCENE: // Szene
begin
for i:=1 to lastchan do
begin
if (Data1[i]>-1) then
recordchannelvalue[i]:=maxres-Data1[i]
else
recordchannelvalue[i]:=-1;
end;
audioeffektplayerform.RecordAudioeffekt(Data2);
end;
MSG_AUDIOEFFECTPLAYERRECORD: // Boolean
begin
end;
MSG_SYSTEMVOLUME: // Integer
begin
//Bass_SetVolume(round((Data1/maxres)*100));
masterform.volumeslider.position:=100-round((Data1/maxres)*100);
end;
MSG_SYSTEMMUTE: // Boolean
begin
if Data1 then
Bass_SetVolume(0)
else
Bass_SetVolume(100-masterform.volumeslider.position);
end;
MSG_GRANDMASTER: // Integer
begin
masterform.dimmermaster.Position:=round(((maxres-Data1)/maxres)*100);
end;
MSG_FLASHMASTER: // Integer
begin
masterform.flashmaster.position:=(maxres-Data1);
end;
MSG_SPEEDMASTER:
begin
masterform.speedmaster.position:=(512-Data1);
end;
MSG_ADDLOGFILEENTRY: // String
begin
debuglistbox.ItemIndex:=debuglistbox.Items.Add('['+inttostr(debuglistbox.Items.Count)+'] ['+Timetostr(now)+'] ['+Datetostr(now)+'] PLUGIN: '+Data1);
debuglistbox.Items.SaveToFile(workingdirectory+'\PC_DIMMER.log');
end;
MSG_SYSTEMSPEED: // Word
begin
if (beatform.Temposourcebox.ItemIndex=2) then
begin
beatform.temposlider.Position:=Data1;
end;
end;
MSG_NEW: ToolButton1Click(nil);
MSG_OPEN: openproject(Data1, false);
MSG_SAVE: saveproject(false,false);
MSG_BEATIMPULSE: // Boolean
begin
if (beatform.Temposourcebox.ItemIndex=2) then
begin
if beatform.beat.color=clMaroon then
begin
beatform.beat.Color:=clBlack;
end else
begin
beatform.beat.Color:=clMaroon;
end;
ExecuteBeat(nil);
end;
end;
MSG_ACTUALCHANNELVALUE: senddata(Data1, maxres-Data2, maxres-Data2, 0);
MSG_STARTSCENE: StartScene(StringToGUID(string(data1)),false,false, -1);
MSG_STOPSCENE: StopScene(StringToGUID(string(data1)));
MSG_MIDIIN:
begin
// mididata:=VarArrayCreate([0,2], varInteger);
// mididata:=data1;
GetMidi(data1[0], data1[1], data1[2]);
end;
MSG_MIDIOUT:
begin
SendMidi(data1[0], data1[1], data1[2]);
end;
MSG_OPENLIBRARY:
begin
setlength(szenenverwaltung_formarray,length(szenenverwaltung_formarray)+1);
szenenverwaltung_formarray[length(szenenverwaltung_formarray)-1]:=Tszenenverwaltungform.Create(mainform);
szenenverwaltung_formarray[length(szenenverwaltung_formarray)-1].Positionselection:=StringToGUID(data1);
if (szenenverwaltung_formarray[length(szenenverwaltung_formarray)-1].showmodal=mrOK) then
begin
if szenenverwaltung_formarray[length(szenenverwaltung_formarray)-1].VST.SelectedCount>0 then
begin
SzenenData:=szenenverwaltung_formarray[length(szenenverwaltung_formarray)-1].VST.GetNodeData(szenenverwaltung_formarray[length(szenenverwaltung_formarray)-1].VST.FocusedNode);
SendMSG(MSG_LIBRARYVALUE, mainform.GetSceneInfo2(SzenenData^.ID,'name'), GUIDToString(SzenenData^.ID));
end;
end;
szenenverwaltung_formarray[length(szenenverwaltung_formarray)-1].Free;
setlength(szenenverwaltung_formarray,length(szenenverwaltung_formarray)-1);
end;
// PluginScenes
MSG_CREATEPLUGINSCENE:
begin
setlength(pluginszenen, length(pluginszenen)+1);
pluginszenen[length(pluginszenen)-1].ID:=StringToGUID(string(Data1));
pluginszenen[length(pluginszenen)-1].Name:=string(Data2);
pluginszenen[length(pluginszenen)-1].Category:='';
// Szenenverwaltung aktualisieren
if szenenverwaltung_formarray[0].Showing then
szenenverwaltung_formarray[0].FormShow(nil);
end;
MSG_REFRESHPLUGINSCENE:
begin
for i:=0 to length(pluginszenen)-1 do
begin
if IsEqualGUID(StringToGUID(string(Data1)), pluginszenen[i].ID) then
begin
pluginszenen[i].Name:=string(Data2);
// Szenenverwaltung aktualisieren
if szenenverwaltung_formarray[0].Showing then
szenenverwaltung_formarray[0].FormShow(nil);
break;
end;
end;
end;
MSG_REMOVEPLUGINSCENE:
begin
for i:=0 to length(pluginszenen)-1 do
begin
if IsEqualGUID(StringToGUID(string(Data1)), pluginszenen[i].ID) then
begin
for j:=i to length(pluginszenen)-2 do
begin
pluginszenen[j].ID:=pluginszenen[j+1].ID;
pluginszenen[j].Name:=pluginszenen[j+1].Name;
pluginszenen[j].Category:=pluginszenen[j+1].Category;
end;
setlength(pluginszenen, length(pluginszenen)-1);
// Szenenverwaltung aktualisieren
if szenenverwaltung_formarray[0].Showing then
szenenverwaltung_formarray[0].FormShow(nil);
break;
end;
end;
end;
MSG_STARTPLUGINSCENE:
begin
// nur von Plugins auswerten
end;
MSG_STOPPLUGINSCENE:
begin
// nur von Plugins auswerten
end;
MSG_EDITPLUGINSCENE:
begin
// nur von Plugins auswerten
end;
MSG_REGISTERPLUGINCOMMAND:
begin
setlength(Befehlssystem[13].Steuerung, length(Befehlssystem[13].Steuerung)+1);
Befehlssystem[13].Steuerung[length(Befehlssystem[13].Steuerung)-1].Bezeichnung:=string(Data2);
Befehlssystem[13].Steuerung[length(Befehlssystem[13].Steuerung)-1].GUID:=StringToGUID(string(Data1));
Befehlssystem[13].Steuerung[length(Befehlssystem[13].Steuerung)-1].InputValueOnly:=false;
Befehlssystem[13].Steuerung[length(Befehlssystem[13].Steuerung)-1].IntegerArgCount:=0;
Befehlssystem[13].Steuerung[length(Befehlssystem[13].Steuerung)-1].StringArgCount:=0;
Befehlssystem[13].Steuerung[length(Befehlssystem[13].Steuerung)-1].GUIDArgCount:=0;
end;
MSG_SETCOLOR: geraetesteuerung.set_color(StringToGUID(string(Data1)), data2[0], data2[1], data2[2], 0, 0); // Data1=ID, Data2=array[0..2] of byte (=R,G,B)
MSG_SETDIMMER: geraetesteuerung.set_dimmer(StringToGUID(string(Data1)), data2); // Data1=ID, Data2=byte
MSG_SETSTROBE: geraetesteuerung.set_strobe(StringToGUID(string(Data1)), data2); // Data1=ID, Data2=byte
MSG_SETSHUTTER: geraetesteuerung.set_shutter(StringToGUID(string(Data1)), data2); // Data1=ID, Data2=byte (0=off, 255=on)
MSG_SETGOBOROT1: geraetesteuerung.set_gobo1rot(StringToGUID(string(Data1)), data2); // Data1=ID, Data2=byte (0=off, 255=on)
MSG_SETGOBOROT2: geraetesteuerung.set_gobo2rot(StringToGUID(string(Data1)), data2); // Data1=ID, Data2=byte (0=off, 255=on)
MSG_SETPRISMA: geraetesteuerung.set_prisma(StringToGUID(string(Data1)), data2); // Data1=ID, Data2=byte (0=off, 255=on)
MSG_SETPRISMAROT: geraetesteuerung.set_prismarot(StringToGUID(string(Data1)), data2); // Data1=ID, Data2=byte (0=off, 255=on)
MSG_SETIRIS: geraetesteuerung.set_iris(StringToGUID(string(Data1)), data2); // Data1=ID, Data2=byte (0=off, 255=on)
MSG_STARTCOMMAND:
begin
TerminalSystem.BefehlsTyp:=StringToGUID(data1[0]);
TerminalSystem.IntegerArg1:=strtoint(data1[1]);
TerminalSystem.IntegerArg2:=strtoint(data1[2]);
TerminalSystem.StringArg1:=data1[3];
TerminalSystem.StringArg2:=data1[4];
TerminalSystem.GUID1:=StringToGUID(data1[5]);
TerminalSystem.GUID2:=StringToGUID(data1[6]);
StartBefehl(StringToGUID('{46368186-DF3D-467A-9792-DAC6B03A21E3}'), integer(data2));
end;
end;
end;
end;
Bei MSG_OPENLIBRARY wird zunächst eine Instanz der Bibliothek erzeugt, dann die ID in eine GUID umgewandelt und der Selektion übergeben und anschließend die Bibliothek angezeigt. Sobald man auf OK klickt, wird geprüft, ob eine Szene ausgewählt wurde - wenn nicht wird die Verwaltung ohne Nachricht wieder gelöscht. Wird aber eine Szene ausgewählt, dann wird zum Plugin wieder ein SendMSG gesendet mit den entsprechenden Werten. Dann wieder entsprechend die Szenenverwaltung entfernt.
viele Grüße,
Christian
Re: Plugin in FreePascal / Lazarus
Verfasst: 16.01.2012, 20:49
von Ingo
Hi Christian!
Vielen Dank für deine Bemühungen. Letztendlich musste ich feststellen, dass ich mir wieder nur selbst im Weg gestanden habe. Mein Textbuch-Plugin ist nämlich immer durcheinander gekommen, wenn es eine MSG_LIBRARYVALUE bekommen hat. Damals habe ich gedacht, jedes Plugin würde nur seine eigenen Bibliothekenanfragen beantwortet bekommen. Dem ist aber eben nicht so. Die Textbuch-Quelltexte liegen aber zuhause, weshalb ich das eben erstmal deaktivieren muss, dann gehts.
Nun war da aber noch eine zweite Sache, die ich angenommen habe, und zwar dass Plugins über das Messagesystem über Szenenstarts usw. informiert werden, die bräuchte nämlich mein Backtrack-Plugin, welches
hier seinen Ursprung hat. Das heißt, ich würde dich nun bitten, einfach alle Szenenstart/Stop sowie Beatevents an mein Plugin weiterzuleiten.
Viele Grüße und nochmal danke für die Unterstützung,
Ingo
Re: Plugin in FreePascal / Lazarus
Verfasst: 17.01.2012, 08:45
von Christian
Hi Ingo,
der Start von Pluginszenen wird natürlich per Nachrichtensystem übertragen - der Start von "normalen" Szenen bislang nicht. Du bräuchtest auch den Start von "normalen" Szenen als Nachricht? Sollte eigentlich machbar sein, aber was genau hast du vor?
viele Grüße,
Christian
Re: Plugin in FreePascal / Lazarus
Verfasst: 17.01.2012, 12:24
von Ingo
Hi Christian!
Ja, ich brauche die Starts und Stopps normaler Szenen. Wie gesagt, ich möchte ein Midi-Backtrack-Plugin schreiben, welches alle Events des PC_DIMMERs zum Triggern von Midi-Backtracks benutzen kann. Wie im
anderen Thread vorgeschlagen, zum Beispiel für eine Buttonmatrix mit Buttonbeleuchtung, sodass zum Beispiel der Status eines Effekts mit verschiedenen Farben angezeigt werden kann. Ich dachte, es wäre einfacher ein Plugin zu schreiben als dich zu bitten es noch in die Midi-Einstellungen zu implementieren. Das ganze ist auch so gut wie fertig - mir fehlen halt nur noch die Events.
Interessant wären natürlich auch Beatimpulse sowie Master (sodass man einen Master auf einer Leiste Buttons abbilden kann usw.). Bis jetzt bekomme ich nur Speed- und Flashmaster.
Viele Grüße,
Ingo
Re: Plugin in FreePascal / Lazarus
Verfasst: 17.01.2012, 13:49
von Christian
OK, das sollte alles ohne größeren Aufwand machbar sein. Ich bin allerdings erst wieder am Freitag zu Hause. Falls dir noch etwas einfällt, schreib mir vielleicht eine Liste der Events, welche dir noch fehlen. Bislang wären es ja:
- Szenen start/stop
- Beatimpuls
- Master
bis dann,
Christian
Re: Plugin in FreePascal / Lazarus
Verfasst: 17.01.2012, 14:27
von Ingo
Okay, kein Problem, muss Raphael halt so lange warten

.
Er hatte auch Flash-Tasten erwähnt, wie ist das am besten zu lösen? Einfach mit einem aktuellen Kanalwert oder gibt es einen besseren Weg?
Ingo
Re: Plugin in FreePascal / Lazarus
Verfasst: 21.01.2012, 13:16
von Christian
Hallo zusammen,
ich hab das Hauptprogramm nun angepasst und einige andere Dinge ebenfalls noch erledigt. Ihr könnt die Datei hier herunterladen:
ftp://78.46.159.60/PC_DIMMER2012/PC_DIMMER2012.zip
Dateigröße: ca. 7,5MB
Es handelt sich hier lediglich um die PC_DIMMER.EXE. Es wird also eine bestehende PC_DIMMER-Installation benötigt!!!
ftp://78.46.159.60/PC_DIMMER2012/PC_DIM ... _Setup.exe
Dateigröße: 30,0MB
Das ist das komplette Setup für den PC_DIMMER2012 v5.1.0. Das ist erstmal nur zum Testen. Es kommen noch einige andere Änderungen zu v5.1.0 hinzu.
viele Grüße,
Christian