Seite 1 von 2
Funktion aus mainApp in DLL nutzen?
Verfasst: 24.02.2009 19:22
von Blackskyliner
Hallo.
Meine Frage bezieht sich mal wieder auf DLL's.
Gibt es eine Möglichkeit aus meiner DLL eine Funktion des Programms aufzurufen, in welches ich die DLL einbinde?
MFG
Blackskyliner
Verfasst: 24.02.2009 19:37
von ts-soft
CallFunctionFast()
Verfasst: 24.02.2009 19:39
von Thorium
Jap gibt es. Wenn ich mich nicht irre geht das am besten mit den Interfaces. Hatte das aber nicht damit hinbekommen also selbst gebaut.
Hatte mal ein Plug-in System entworfen.
in Core-Anwendung
Code: Alles auswählen
;Prozeduren die Plug-ins zur Verfügung gestellt werden
Structure S2HackIt_FunctionTable
*PlugInCallback
*ConsoleOutput
*FreezeS2
*UnFreezeS2
*PatchS2
EndStructure
Global FunctionTable.S2HackIt_FunctionTable
Procedure BuildFunctionTable()
FunctionTable\PlugInCallback = @PlugInCallback()
FunctionTable\ConsoleOutput = @ConsoleOutput()
FunctionTable\FreezeS2 = @FreezeS2()
FunctionTable\UnFreezeS2 = @UnFreezeS2()
FunctionTable\PatchS2 = @PatchS2()
EndProcedure
;Aufruf einer Init-Prozedur des Plug-ins vom Core aus
CallFunction(PlugInLib,"Init",#Version,@FunctionTable,@VariableTable)
;in der VariableTable können Variablen geshart werden, hab ich aber nicht genutzt
im Plug-in
Code: Alles auswählen
Structure S2HackIt_FunctionTable
*PlugInCallback
*ConsoleOutput
*FreezeS2
*UnFreezeS2
*PatchS2
EndStructure
Global *S2HackIt.S2HackIt_FunctionTable
ProcedureDLL Init(S2HackItVersion.l,*FunctionTable,*VariableTable)
If S2HackItVersion = 1
S2Pid = GetCurrentProcessId_()
*S2HackIt = *FunctionTable
CallFunctionFast(*S2HackIt\ConsoleOutput,"MemPatcher v1.01 loaded")
CallFunctionFast(*S2HackIt\PlugInCallback)
EndIf
EndProcedure
Sollte eigentlich selbsterklärend sein. Wenn nicht einfach nochmal nachfragen.
Den kompletten Source des Projekts hab ich vorhin veröffentlicht:
http://www.purebasic.fr/german/viewtopic.php?t=19250
Verfasst: 24.02.2009 20:17
von Blackskyliner
Mein derzeitiger Anlauf war folgender:
Natürlich nur ausschnittsweise..
Code: Alles auswählen
Structure moduleMessage_struct
message.s
EndStructure
Structure moduleMessages_struct
count.l
*moduleMessage.moduleMessage_struct
EndStructure
Procedure progressModulesInteraction()
Protected *f, *r.moduleMessages_struct;
ForEach loadedModules()
If loadedModules()\isLoaded
*f = GetFunction(loadedModules()\id, "getModuleMessages")
If *f
*r = CallFunctionFast(*f);
Debug *r\count
EndIf
EndIf
Next
EndProcedure
Diese FUnktion wird aufgerufen und _soll_ eine Liste in *r übergeben bekomen... loadedModules()\id ist die durch OpenLibary geöffnete dll
Doch statt 1 bekomm ich 8 zurückgegeben.
hier noch der COde desPlugins
Code: Alles auswählen
EnableExplicit
;{ == Declare all Functions
; (De)Init
DeclareDLL AttachProcess(*nullVar)
DeclareDLL Worker(*nullVar)
DeclareDLL DetachProcess(*nullVar)
; Main
DeclareDLL DLLMain()
;Moduleinterface
DeclareDLL getModuleMessages()
;}
;{ == Moduleinterface Structures ==;
Structure moduleMessage_struct
message.s
EndStructure
Structure moduleMessages_struct
count.l
*moduleMessage.moduleMessage_struct
EndStructure
;}
;{ == Global Things ==;
Global NewList moduleMessages.moduleMessage_struct();
;}
;{ == (De)Init Procedures ==;
ProcedureDLL AttachProcess(*nullVar)
;Initialize all Variables und Call DLLMain
;to avoid the Call Loop documented on MSDN
DLLMain()
EndProcedure
ProcedureDLL DLLMain()
AddElement(moduleMessages())
moduleMessages()\message = "OMFG Y O U G O T I T!";
;Create the Worker Thread
CreateThread(@Worker(), 0)
EndProcedure
ProcedureDLL DetachProcess(*nullVar)
;Clear all initialized Variables
EndProcedure
;}
;{ == Main Worker ==;
ProcedureDLL Worker(*nullVar)
;Say that you loaded... Hopefully sometimes...
MessageRequester("DLL", "Successful loaded.")
EndProcedure
;}
;{ == Moduleinterface Functions ==;
ProcedureDLL getModuleMessages()
Define.moduleMessages_struct moduleMessage
moduleMessage\count = CountList(moduleMessages())
moduleMessage\moduleMessage = @moduleMessages()
;MessageRequester("Count", Str(moduleMessage\count) )
ProcedureReturn moduleMessage
EndProcedure
;}
Wäre nett wenn du das mal drüberschnellen könntest. Das soll halt am ende eine PluginMessage Quenue werden. Durch das werden dann registrierte ObserverPlugins immer benachrichtigt, wenn irgendwas geupdated wurde. Auch wird die message_struc noch größer als nur message.s
Sorry für diese doofe Nahmensgebung... Immer bissle aufs s achten, damit man weiß ob Mehrzahl(linkedList) oder Einzahl(RückgabeVariable)
Versuche nähmlich die MainCalls so gering wie irgend möglich zu halten. Aber deine Idee mit der übergabe ist auch ganz nett, mal sehn, wenn das nich Klappt werde ich warscheinlich deins nutzen.
Die Liste kann ich ja leider nicht übergeben, da die Module ja Thread-based sind und es zu einem MemoryAccessViolation kommen könnte...
Verfasst: 24.02.2009 21:10
von Thorium
Das Problem hat mit der Speicherverwaltung zutun.
So funktionierts:
Code: Alles auswählen
;{ == Moduleinterface Functions ==;
ProcedureDLL getModuleMessages()
Define.moduleMessages_struct *moduleMessage
*moduleMessage = AllocateMemory(SizeOf(moduleMessages_struct))
*moduleMessage\count = CountList(moduleMessages())
*moduleMessage\moduleMessage = @moduleMessages()
ProcedureReturn *moduleMessage
EndProcedure
;}
Verfasst: 24.02.2009 21:18
von Thorium
Ach, wenn du das so machst, musst aber drauf achten den Speicher mit FreeMemory auch wieder freizugeben, sonst bastelst du dir ein fettes Memory Leak.
Ob das mit dem übergeben der Liste funktioniert hab ich mich mal net getraut zu testen.

Verfasst: 24.02.2009 21:34
von Blackskyliner
Lohnt es sich eigentlich einen Mutex zu erstellen, im Main und dann die Adresse zu diesem Mutex an dieModule zu übergeben zusammen mit einer im Main Programm erstellten liste?? Das sollte dann ja den Prozess vereinfachern nur ist das "sauber"?
Verfasst: 24.02.2009 22:38
von cxAlex
Bei Mutexen must du aufpassen wie du sie Lockst und Unlockst, sonst kann es leicht zu einem Deathlock kommen. Ich hab vor in nächster Zeit mal ein Tutorial über Threads, Mutex und Semaphoren in PB zu schreiben, für was man Sie verwenden kann und wann was eher sinnvoll ist.
Verfasst: 24.02.2009 23:42
von Blackskyliner
Da denk ich mal pass ich schon auf, da ja nur Ein Script _direkt_ den lock zu gleichen Zeit anfordern kann... zumal ich einen AntiDeadlock Thread in den DLLs oder in meinem Main starten könnte... k.A.
Bin sher gespannt auf dein Tutorial
EDIT:
Ich machs nun auf deine Weise @Thorium und stelle dem Plugin einfach die FUnktionen direkt zur Verfügung. Mal sehn ob alles so klappt wie ichs mir denke. Danke dafür, das vereinfacht einfach alles

Verfasst: 25.02.2009 02:04
von Blackskyliner
Nun doch noch ein Problem, sorry für den Doppelpost.
sharedStructures.pbi
Code: Alles auswählen
Structure sharedFunctions_struct
; Communication functions
*sendMainMessage
*sendModuleMessage
*sendObserverMessage
; Register GUI-Callbacks
*registerObserver
*unregisterObserver
EndStructure
pluginLoader.pb
Code: Alles auswählen
XIncludeFile "sharedStructures.pbi"
;[ ... ]
;{ == sharedFucntions ==
Global sharedFunctions.sharedFunctions_struct
sharedFunctions\sendMainMessage = @sendMainMessage()
sharedFunctions\sendModuleMessage = @sendModuleMessage()
sharedFunctions\sendObserverMessage = @sendObserverMessage()
sharedFunctions\registerObserver = @registerObserver()
sharedFunctions\unregisterObserver = @unregisterObserver()
Procedure sendMainMessage(message$)
MessageRequester("Main Message", message$)
EndProcedure
Procedure sendModuleMessage(module$, message$)
EndProcedure
Procedure sendObserverMessage(message$)
EndProcedure
Procedure registerObserver()
EndProcedure
Procedure unregisterObserver()
EndProcedure
;}
; [ ... ]
Procedure loadModules()
Protected id.l
ForEach loadedModules()
If loadedModules()\shouldLoaded = #True And loadedModules()\isLoaded = #False
id = OpenLibrary(#PB_Any, moduleDirectory$+loadedModules()\name)
CallFunction(id, "registerSharedFunctions", @sharedFunctions)
loadedModules()\id = id;
loadedModules()\isLoaded.b = #True;
EndIf
If loadedModules()\shouldLoaded = #False And loadedModules()\isLoaded = #True
CloseLibrary(loadedModules()\id)
loadedModules()\id = #Null;
loadedModules()\isLoaded.b = #False;
EndIf
Next
EndProcedure
; [ ... ]
plugin.pb
Code: Alles auswählen
XIncludeFile "sharedStructures.pbi"
EnableExplicit
;{ == Declare all Functions
; (De)Init
DeclareDLL AttachProcess(*nullVar)
DeclareDLL Worker(*nullVar)
DeclareDLL DetachProcess(*nullVar)
; Main
DeclareDLL DLLMain()
;Module fucntions
DeclareDLL registerMainVars(*local_QuenueList, quenueMutex)
;}
;{ == Global Things ==;
Global *sharedFunctions.sharedFunctions_struct
;}
;{ == (De)Init Procedures ==;
ProcedureDLL AttachProcess(*nullVar)
;Initialize all Variables und Call DLLMain
;to avoid the Call Loop documented on MSDN
*sharedFunctions = #Null
DLLMain()
EndProcedure
ProcedureDLL registerSharedFunctions(*FunctionTable)
*sharedFunctions = *FunctionTable
EndProcedure
ProcedureDLL DLLMain()
;Create the Worker Thread
CreateThread(@Worker(), 0)
EndProcedure
ProcedureDLL DetachProcess(*nullVar)
;Clear all initialized Variables
EndProcedure
;}
;{ == Main Worker ==;
ProcedureDLL Worker(*nullVar)
;Wait to get the sharedFunctions
Delay(1500)
If *sharedFunctions
MessageRequester("DLL", "Successful loaded.")
CallFunctionFast(*sharedFunctions\sendMainMessage, "Und sie dreht sich doch!")
EndIf
EndProcedure
;}
Mein Fehler istfolgendermaßen. Ich bekomme den MessageRequester angezeigt, der mit sagt erfolgreich geladen... Aber dann schmiert der ab mit Invalid Memory Access auf Line 0. Daraus kann ich so viel ableiten, dass er die Funktionen scheinbar doch nicht so recht übergeben bekommen hat. Was mache ich falsch?
BTW: Die Adressen sind laut meinem Debugging aber in der Main und der DLL die gleichen!
Danke für jede Hilfe
MFG
Blackskyliner
EDIT:
Wie ich ihn doch hasse... den Debugger

[Also zumidnest in 4.2] Kann das jmd. mit dem Debugger von 4.3 Testen, weil wenns da mit geht wärs ja ganz nett... SOnst muss ich halt den Debugger an bestimmten stellen ausstellen oder gar Ganz Off lassen.... :-\
EDIT2: Hier der Link zum Projekt unter Anwendungen
http://www.purebasic.fr/german/viewtopi ... 593#233593