Funktion aus mainApp in DLL nutzen?

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Funktion aus mainApp in DLL nutzen?

Beitrag 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
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

CallFunctionFast()
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
Thorium
Beiträge: 1722
Registriert: 12.06.2005 11:15
Wohnort: Germany
Kontaktdaten:

Beitrag 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
Zu mir kommen behinderte Delphine um mit mir zu schwimmen.

Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke! Bild
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Beitrag 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...
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Benutzeravatar
Thorium
Beiträge: 1722
Registriert: 12.06.2005 11:15
Wohnort: Germany
Kontaktdaten:

Beitrag 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
;}
Zu mir kommen behinderte Delphine um mit mir zu schwimmen.

Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke! Bild
Benutzeravatar
Thorium
Beiträge: 1722
Registriert: 12.06.2005 11:15
Wohnort: Germany
Kontaktdaten:

Beitrag 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. :lol:
Zu mir kommen behinderte Delphine um mit mir zu schwimmen.

Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke! Bild
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Beitrag 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"?
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

Beitrag 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.
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Beitrag 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 ;)
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Beitrag 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
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Antworten