Plugin in FreePascal / Lazarus

Planungen und Wünsche die Entwicklung betreffend
Antworten
Ingo
< PC_DIMMER >
Beiträge: 533
Registriert: 19.03.2009, 17:49
Wohnort: Bad Hersfeld bzw. Stuttgart

Plugin in FreePascal / Lazarus

Beitrag von Ingo » 10.01.2012, 18:45

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 :x ) ... 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 :wink:

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.

Benutzeravatar
admin
PC_DIMMER-Entwickler
Beiträge: 1812
Registriert: 12.11.2007, 09:30
Wohnort: Knw.-Remsfeld
Kontaktdaten:

Re: Plugin in FreePascal / Lazarus

Beitrag von admin » 11.01.2012, 08:25

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

Ingo
< PC_DIMMER >
Beiträge: 533
Registriert: 19.03.2009, 17:49
Wohnort: Bad Hersfeld bzw. Stuttgart

Re: Plugin in FreePascal / Lazarus

Beitrag von Ingo » 11.01.2012, 19:44

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

Benutzeravatar
admin
PC_DIMMER-Entwickler
Beiträge: 1812
Registriert: 12.11.2007, 09:30
Wohnort: Knw.-Remsfeld
Kontaktdaten:

Re: Plugin in FreePascal / Lazarus

Beitrag von admin » 11.01.2012, 23:12

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

Ingo
< PC_DIMMER >
Beiträge: 533
Registriert: 19.03.2009, 17:49
Wohnort: Bad Hersfeld bzw. Stuttgart

Re: Plugin in FreePascal / Lazarus

Beitrag von Ingo » 16.01.2012, 20:49

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

Benutzeravatar
admin
PC_DIMMER-Entwickler
Beiträge: 1812
Registriert: 12.11.2007, 09:30
Wohnort: Knw.-Remsfeld
Kontaktdaten:

Re: Plugin in FreePascal / Lazarus

Beitrag von admin » 17.01.2012, 08:45

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

Ingo
< PC_DIMMER >
Beiträge: 533
Registriert: 19.03.2009, 17:49
Wohnort: Bad Hersfeld bzw. Stuttgart

Re: Plugin in FreePascal / Lazarus

Beitrag von Ingo » 17.01.2012, 12:24

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

Benutzeravatar
admin
PC_DIMMER-Entwickler
Beiträge: 1812
Registriert: 12.11.2007, 09:30
Wohnort: Knw.-Remsfeld
Kontaktdaten:

Re: Plugin in FreePascal / Lazarus

Beitrag von admin » 17.01.2012, 13:49

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

Ingo
< PC_DIMMER >
Beiträge: 533
Registriert: 19.03.2009, 17:49
Wohnort: Bad Hersfeld bzw. Stuttgart

Re: Plugin in FreePascal / Lazarus

Beitrag von Ingo » 17.01.2012, 14:27

Okay, kein Problem, muss Raphael halt so lange warten :frech: .
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

Benutzeravatar
admin
PC_DIMMER-Entwickler
Beiträge: 1812
Registriert: 12.11.2007, 09:30
Wohnort: Knw.-Remsfeld
Kontaktdaten:

Re: Plugin in FreePascal / Lazarus

Beitrag von admin » 21.01.2012, 13:16

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

Antworten