Seite 1 von 1

selbst erstellte DLL und UseGadgetList darin

Verfasst: 25.08.2014 12:11
von Makke
Hallo zusammen,

ich habe (eigentlich für Linux, soll aber auch unter WIndows laufen) eine DLL erstellt die Animationen auf einem ImageGadget abspielt. Sinn und Zweck ist die GUI für unterschiedliche Programme grafisch etwas aufzuhübschen, ohne den ganzen Code in andere Programme zu übernehmen sondern einfach nur die DLL einzubinden und die Animationen daraus zu starten (die Grafiken sind ebenfalls in der DLL enthalten).

Ich wollte einfach folgenden Befehl zur Verfügung stellen: AnimImageGadget(WindowID, x, y, AnimName, fps, width, height)

Innerhalb der Procedure benutze ich dann UseGadgetList(windowID), aber genau das funktioniert nicht. Zum besseren Verständnis mal der Code wie ich die DLL/so einbinde:

Code: Alles auswählen

Import "animatedimages.so"
  AnimImageGadget_Initialize()
  AnimImageGadget.i(WindowID.i, Handle.i, X.l, Y.l, AnimName.s, Width.l=0, Height.l=0, DelayBetween.l=0, Decoration.l=0)
  AnimImageGadget_GetLastError() ;??? .s
EndImport

If OpenLibrary(0, "animatedimages.so")
  CallFunction(0, "AnimImageGadget(Handle.i, X.l, Y.l, AnimName.s, Width.l=0, Height.l=0, DelayBetween.l=0, Decoration.l=0)")
  CloseLibrary(0)
EndIf

Define.l n
AnimImageGadget_Initialize()
If OpenWindow(0, 0, 0, 470, 90, "TEST", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  For n = 0 To 6
    Select Random(2)
      Case 0 : Debug AnimImageGadget(WindowID(0), n, n*64+10, 10, "folder_compare_anim", 0, 0, 0, #PB_Image_Border) : Debug AnimImageGadget_GetLastError()
      Case 1 : Debug AnimImageGadget(WindowID(0), n, n*64+10, 10, "folder_search_anim", 0, 0, 0, #PB_Image_Border)  : Debug AnimImageGadget_GetLastError()
      Case 2 : Debug AnimImageGadget(WindowID(0), n, n*64+10, 10, "wait_anim", 0, 0, 0, #PB_Image_Border)           : Debug AnimImageGadget_GetLastError()
    EndSelect
    Delay(100)
  Next
EndIf

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Wenn ich das starte, erhalte ich leider keine schönen Animationen sondern ein leeres Fenster mit folgenden Fehlermeldungen (Achtung Linux):

Code: Alles auswählen

[12:02:12] Warte auf den Start des Executable...
[12:02:12] Executable-Typ: Linux - x64  (64bit, Unicode, Purifier)
[12:02:12] Executable gestartet.
[12:02:12] [WARNING] test_animimages2.pb (Zeile: 17)
[12:02:12] [WARNING] Gtk (CRITICAL): IA__gtk_fixed_put: assertion 'GTK_IS_FIXED (fixed)' failed
[12:02:12] [WARNING] test_animimages2.pb (Zeile: 17)
[12:02:12] [WARNING] Gtk (CRITICAL): IA__gtk_widget_realize: assertion 'GTK_WIDGET_ANCHORED (widget) || GTK_IS_INVISIBLE (widget)' failed
[12:02:12] [Debug] 40463808
usw...
Der Rückgabewert der DLL ist das Gadget Handle bzw. die ID. AnimImageGadget_GetLastError() sollte eigentlich einen String liefern, das funktioniert aber nicht mit Import, muss ich da einen Pointer zurück liefern ?

Ich bin für alle Tips und Lösungsansätze dankbar.

Re: selbst erstellte DLL und UseGadgetList darin

Verfasst: 25.08.2014 15:11
von Bisonte
Ohne den Code der DLL/so zu sehen wird das schwierig.
Allerdings fällt mir zumindest spontan auf :

(Ich kann nur von Windows aus sprechen...)
Importiert werden eigentlich nur .lib Dateien, nicht die DLL.
Dann öffnest du zusätzlich noch die DLL und rufst (zumindest willst du das wohl) eine
Funktion auf. Callfunction kann so aber nicht funktionieren. (Völlig falscher Aufruf)

Desweiteren muss (wenn die DLL geladen wird) die DLL solange "Open" sein, wie die
Funktionen daraus benutzt werden. Wenn man sie schliesst und danach versucht eine Funktion aufzurufen ist essig...

Ausserdem solltest du (beim DLL nutzen) lieber Prototypes verwenden.
Und die "optionalen" Parameter funktionieren so leider auch nicht.
Da muss für jeden Parameter eine eigene Prozedur in der DLL für existieren, ODER
Man hat eine "Wrapper" Prozedur, die dann fehlendes einträgt.
(Wobei ich glaube mit Prototypes geht das schon...)
Ich versuche mal ein kurzes Beispiel zu basteln, das zeigt was ich meine...

Edit : Hier die Beispiele :

Die Dll ist mit Unicode kompiliert

Code: Alles auswählen

;: TestDLL Windows

Global ReturnString.s = ""

ProcedureDLL BGadget(WindowID, x, y, AnimName.s, fps, width, height)
  
  Protected Result = #False
  Protected OldGadgetList
  
  If IsWindow_(WindowID)
    OldGadgetList = UseGadgetList(WindowID)
    
    Result = ButtonGadget(#PB_Any, x, y, width, height, AnimName)
    
    Result = GadgetID(Result)
    
    UseGadgetList(OldGadgetList)
  EndIf
  
  ProcedureReturn Result
  
EndProcedure
; - Eine "Private" Prozedur, die von aussen nicht erreichbar ist.
Procedure.s BStringFunction(String1.s, String2.s)
  
  Result.s = String1 + "..." + String2 + "...!"
  ProcedureReturn Result
  
EndProcedure
; - Und hier nun die Prozedur, die von aussen erreichbar sein soll
ProcedureDLL.s BString(String1.s, String2.s)
  
  ReturnString = BStringFunction(String1, String2)
  ProcedureReturn ReturnString
  
EndProcedure


das benutzende Programm....

Code: Alles auswählen

Prototype proto_BGadget(WindowID, x, y, AnimName.p-Unicode, fps = 10, width = 100, height = 20)
;                                       ------------------ Automatische Umwandlung weil ich die DLL in unicode kompiliert habe
Prototype proto_BString(String1.p-Unicode, String2.p-Unicode)

If Not OpenLibrary(0, "Test_Dll.dll") : End : EndIf

Global BGadget.proto_BGadget = GetFunction(0, "BGadget") ; BGadget Global Verfügbar machen
Global BStringFunction.proto_BString = GetFunction(0, "BString") 

Procedure.s BString(String1.s, String2.s)
  
  Protected Result, String.s = ""
  
  Result = BStringFunction(String1, String2)
  String = PeekS(Result, -1, #PB_Unicode)
  
  ProcedureReturn String
  
EndProcedure

If Not BGadget : End : EndIf ; Check ob das zuweisen funktioniert hat

OpenWindow(0, 0, 0 , 640, 480, "Test", #PB_Window_SystemMenu)

BGadget(WindowID(0), 10, 10, "Hallö", 0, 300)
Debug BString("Hallo","Du Da")

Repeat
  Event = WaitWindowEvent()
  
Until Event = #PB_Event_CloseWindow
Oder per Import

Code: Alles auswählen

Import "Test_Dll.lib"
  BGadget(WindowID, x, y, AnimName.p-Unicode, fps = 10, width = 100, height = 20) As "BGadget"
  BStringFunction(String1.p-Unicode, String2.p-Unicode) As "BString" 
EndImport

Procedure.s BString(String1.s, String2.s)
  
  Protected Result, String.s = ""
  
  Result = BStringFunction(String1, String2)
  String = PeekS(Result, -1, #PB_Unicode)
  
  ProcedureReturn String
  
EndProcedure

OpenWindow(0, 0, 0 , 640, 480, "Test", #PB_Window_SystemMenu)

BGadget(WindowID(0), 10, 10, "Hallö", 0)
Debug BString("Hallo","Du Da")

Repeat
  Event = WaitWindowEvent()
  
Until Event = #PB_Event_CloseWindow
Und hiermit sage ich, daß die optionalen Parameter dann per Prototype auch funktionieren ;)

Re: selbst erstellte DLL und UseGadgetList darin

Verfasst: 25.08.2014 15:44
von STARGÅTE
In deinem Beispielcode vermisschen sich zwei sachen (wie Bisonte schon erklärt).

Import : EndImport importiert Funktionen direkt in die eigene Kompilierung. Ein OpenLibrary ist nicht nötig!
OpenLibrary() öffnet eine Library außerhalb des Programms. Dann ist kein Import nötig.

Allgemein gilt: Du kannst in der DLL nicht auf die "internen" Ressourcen von PB-Funktionen zugreifen.
Das Nummern/ID System von PB ist ein abgeschlossenes System was nicht DLL-Übergreifen funktioniert.
Ein Image/Sprite/Window usw. welches im MAIN erstellt wurde kann nicht in der DLL benutzt werden und anders rum.

Nur System-Handels sind Übergreifend oder eigene definierte Ressourcen.

Und ja, Rückgabewerte von DLLs sind immer nur Ganz- oder Fließkommazahlen.
Also muss vom String der Pointer zurückgegeben werden (Er muss auch Global sein!) und im Main mit PeekS() gelesen werden.
Auchtung hier Ascii/Unicode.

Re: selbst erstellte DLL und UseGadgetList darin

Verfasst: 25.08.2014 16:29
von mk-soft
Aus DLL Gadgets erstellen geht genau so wenig wie Gadgets aus Thread zu erstellen.
Am besten an das Hauptprogramm eine Nachricht senden um Gadgets zu erstellen.

Hab hier mal ein Beispiel. Muss noch mit UsesGadgetList angepasst werden.

http://www.purebasic.fr/english/viewtop ... nt#p401150

Re: selbst erstellte DLL und UseGadgetList darin

Verfasst: 25.08.2014 16:30
von Bisonte
hab das DLL-Beispiel noch um die Stringrückgabe (die eigentlich keine ist) erweitert.

@mk-soft: Das Problem bei PostEvent() ist, dass dort ebenfalls die PB Nummern als Parameter gefragt sind, und das ist,
wenn man auf diese nicht zugreifen kann, recht schwierig.

Unter Windows kann ich SendMessage_() oder PostMessage_() verwenden, aber bei den anderen OS wüsst ich jetzt nicht wie
ich was an das entsprechende Fenster schicken sollte....

Re: selbst erstellte DLL und UseGadgetList darin

Verfasst: 25.08.2014 16:45
von ts-soft
@Bisonto
Wie wäre es, wenn Du dem link von mk-soft folgst :mrgreen:

Re: selbst erstellte DLL und UseGadgetList darin

Verfasst: 25.08.2014 16:47
von mk-soft
Bisonte hat geschrieben: @mk-soft: Das Problem bei PostEvent() ist, dass dort ebenfalls die PB Nummern als Parameter gefragt sind, und das ist,
wenn man auf diese nicht zugreifen kann, recht schwierig.
Das Hauptprogramm sollte schon wissen welche Gadgetlist verwendet werden muss.
Nach dem erstellen des Gadgets aus dem Hauptprogramm wird die GadgetID (#PB_Any) zurückgeliefert. Diese kann in der DLL dann weiter verwendet werden.

Re: selbst erstellte DLL und UseGadgetList darin

Verfasst: 25.08.2014 17:03
von Bisonte
ts-saft hat geschrieben:@Bisonto
Wie wäre es, wenn Du dem link von mk-soft folgst :mrgreen:
Bin ich, lieber ts-saft :mrgreen: ...
und dort sah ich "nur" PostEvent() um Events zu senden.

Re: selbst erstellte DLL und UseGadgetList darin

Verfasst: 25.08.2014 17:16
von ts-soft
Und ich sah dort: SendEvent
Ist wohl für Threads, aber könnte auch mit DLLs funktionieren.

Re: selbst erstellte DLL und UseGadgetList darin

Verfasst: 26.08.2014 17:50
von Makke
Danke für Eure Tips, Erklärungen und Beispiele. Ich werde die Sache von Bisonte mal genauer unter die Lupe nehmen und schauen was geht. Melde mich hier wieder.