Page 1 sur 3

Gestion des objets (+ exemple)

Publié : mar. 20/juin/2006 9:36
par Dr. Dri
Ce code permet d'utiliser les fonctions internes de PB pour gérer des listes d'objets. C'est pratique pour ceux qui font des userlibs, il suffit d'initialiser une liste d'objets et on peut y créer des objets statiques ou dynamiques (avec #PB_Any)
  • Liste des fonctions:
  • Object_GetOrAllocate(*Objects, Object.l)
  • Object_GetObject(*Objects, Object.l)
  • Object_IsObject(*Objects, Object.l)
  • Object_EnumerateAll(*Objects, EnumerateCallback, *VoidData)
  • Object_EnumerateStart(*Objects)
  • Object_EnumerateNext(*Objects, *ID.Long)
  • Object_EnumerateAbort(*Objects)
  • Object_Free(*Objects, Object.l)
  • Object_Init(StructureSize.l, IncrementStep.l, FreeObjectFunction)
  • Object_GetThreadMemory(MemoryID.l)
  • Object_InitThreadMemory(Size.l, InitFunction, EndFunction)
Il suffit d'inclure ce fichier pour avoir accès aux fonctions

Code : Tout sélectionner

Prototype   ThreadFunction(Param)

Prototype.l ObjectEnumerateAllCallback(Object.l, *Element, *VoidData)
Prototype   ObjectFreeFunction(Object.l)

Structure PB_SimpleList
  *Next    .PB_SimpleList
  *Previous.PB_SimpleList
EndStructure

Structure PB_Object
  StructureSize.l
  IncrementStep.l
  ObjectsNumber.l
  *ListFirstElement.PB_SimpleList

  FreeObject.ObjectFreeFunction

  Current.l
  *CurrentElement.PB_SimpleList

CompilerIf #PB_Compiler_Thread
  IncrementShift.l
  *FirstObjectsArea.PB_SimpleList
  *LastObjectsArea .PB_SimpleList
  ObjectMutex.Critical_Section
CompilerElse
  *ObjectsArea
CompilerEndIf
  
EndStructure

Prototype   PB_Object_GetOrAllocate   (*Object.PB_Object, Object.l)
Prototype   PB_Object_GetObject       (*Object.PB_Object, Object.l)
Prototype   PB_Object_IsObject        (*Object.PB_Object, Object.l)
Prototype   PB_Object_EnumerateAll    (*Object.PB_Object, Callback.ObjectEnumerateAllCallback, *VoidData)
Prototype   PB_Object_EnumerateStart  (*Object.PB_Object)
Prototype   PB_Object_EnumerateNext   (*Object.PB_Object, *ID.Long)
Prototype   PB_Object_EnumerateAbort  (*Object.PB_Object)
Prototype   PB_Object_Free            (*Object.PB_Object, Object.l)
Prototype.l PB_Object_Init            (StructureSize.l, IncrementStep.l, FreeObject.ObjectFreeFunction)
Prototype   PB_Object_GetThreadMemory (MemoryID.l)
Prototype.l PB_Object_InitThreadMemory(Size.l, InitFunction.ThreadFunction, EndFunction.ThreadFunction)

Global Object_GetOrAllocate   .PB_Object_GetOrAllocate
Global Object_GetObject       .PB_Object_GetObject
Global Object_IsObject        .PB_Object_IsObject
Global Object_EnumerateAll    .PB_Object_EnumerateAll
Global Object_EnumerateStart  .PB_Object_EnumerateStart
Global Object_EnumerateNext   .PB_Object_EnumerateNext
Global Object_EnumerateAbort  .PB_Object_EnumerateAbort
Global Object_Free            .PB_Object_Free
Global Object_Init            .PB_Object_Init
Global Object_GetThreadMemory .PB_Object_GetThreadMemory
Global Object_InitThreadMemory.PB_Object_InitThreadMemory

!extrn _PB_Object_GetOrAllocateID@8
!extrn _PB_Object_GetObject@8
!extrn _PB_Object_IsObject@8
!extrn _PB_Object_EnumerateAll@12
!extrn _PB_Object_EnumerateStart@4
!extrn _PB_Object_EnumerateNext@8
!extrn _PB_Object_EnumerateAbort@4
!extrn _PB_Object_FreeID@8
!extrn _PB_Object_Init@12
!extrn _PB_Object_GetThreadMemory@4
!extrn _PB_Object_InitThreadMemory@12

!MOV [v_Object_GetOrAllocate]   , _PB_Object_GetOrAllocateID@8
!MOV [v_Object_GetObject]       , _PB_Object_GetObject@8
!MOV [v_Object_IsObject]        , _PB_Object_IsObject@8
!MOV [v_Object_EnumerateAll]    , _PB_Object_EnumerateAll@12
!MOV [v_Object_EnumerateStart]  , _PB_Object_EnumerateStart@4
!MOV [v_Object_EnumerateNext]   , _PB_Object_EnumerateNext@8
!MOV [v_Object_EnumerateAbort]  , _PB_Object_EnumerateAbort@4
!MOV [v_Object_Free]            , _PB_Object_FreeID@8
!MOV [v_Object_Init]            , _PB_Object_Init@12
!MOV [v_Object_GetThreadMemory] , _PB_Object_GetThreadMemory@4
!MOV [v_Object_InitThreadMemory], _PB_Object_InitThreadMemory@12
Un exemple d'utilisation, en espérant que ca aide...

Code : Tout sélectionner

IncludeFile "Object.pbi"

;la structure qui contient les
;informations sur les timers
Structure Timer
  Event.l
  Window.l
  Elapse.l
EndStructure

;il faut que ce soit global ^^
;ou alors shared dans chaque fonction
Global TimerObjects

;la fonction la plus importante, sans elle
;pas d'objets statiques/dynamiques
Procedure.l FreeTimer(Timer.l)
  Protected Free.l = #False, *Timer.Timer
  
  If Timer <> #PB_Any And Object_IsObject(TimerObjects, Timer)
    *Timer = Object_GetObject(TimerObjects, Timer)
  EndIf
  
  If *Timer And IsWindow(*Timer\Window)
    Free = KillTimer_(WindowID(*Timer\Window), *Timer\Event)
    Object_Free(TimerObjects, Timer)
  EndIf
  
  ProcedureReturn Free
EndProcedure

;Retourne "non-zero" si le timer a été créé
;Retourne l'index du timer si Timer = #PB_Any
Procedure.l CreateTimer(Timer.l, Window.l, Event.l, Elapse.l)
  Protected Create.l = #Null, *Timer.Timer
  
  If IsWindow(Window) And Event
    FreeTimer(Timer)
    *Timer = Object_GetOrAllocate(TimerObjects, Timer)
  EndIf
  
  If *Timer
    SetTimer_(WindowID(Window), Event, Elapse, #Null)
    *Timer\Event  = Event
    *Timer\Window = Window
    *Timer\Elapse = Elapse
  EndIf
  
  If Timer = #PB_Any
    Create = *Timer
  ElseIf *Timer
    Create = *Timer\Event
  EndIf
  
  ProcedureReturn Create
EndProcedure

;trois fonctions pour meubler
Procedure.l GetTimerEvent(Timer.l)
  Protected Event.l = #PB_Any, *Timer.Timer
  
  *Timer = Object_GetObject(TimerObjects, Timer)
   
  If *Timer And IsWindow(*Timer\Window)
    Event = *Timer\Event
  EndIf
  
  ProcedureReturn Event
EndProcedure

Procedure.l GetTimerWindow(Timer.l)
  Protected Window.l = #PB_Any, *Timer.Timer
  
  *Timer = Object_GetObject(TimerObjects, Timer)
   
  If *Timer And IsWindow(*Timer\Window)
    Window = *Timer\Window
  EndIf
  
  ProcedureReturn Window
EndProcedure

Procedure.l GetTimerElapse(Timer.l)
  Protected Elapse.l = #PB_Any, *Timer.Timer
  
  *Timer = Object_GetObject(TimerObjects, Timer)
   
  If *Timer And IsWindow(*Timer\Window)
    Elapse = *Timer\Elapse
  EndIf
  
  ProcedureReturn Elapse
EndProcedure

;si on fait une lib autant
;créer les évennements qui vont avec ^^
#PB_Event_Timer = #WM_TIMER

;retourne le numéro de timer (#PB_Any s'il n'existe pas)
Procedure.l EventTimer()
  Protected Window.l, Event.l, Temp.l
  Protected Timer.l = #PB_Any, *Timer.Timer
  
  Window = EventWindow()
  Event  = EventwParam()
  
  Object_EnumerateStart(TimerObjects)
  
  While Object_EnumerateNext(TimerObjects, @Temp)
    *Timer = Object_GetObject(TimerObjects, Temp)
    
    If *Timer\Window = Window And *Timer\Event = Event
      Object_EnumerateAbort(TimerObjects)
      Timer = Temp
    EndIf
  Wend
  
  ProcedureReturn Timer
EndProcedure

;crée la liste d'objets des timers,
;je ne sais pas à quoi correspond le 2e argument
TimerObjects = Object_Init(SizeOf(Timer), 1, @FreeTimer())

;fin de la "lib"

;-------------------------------------------------------------------------------

;début du programme

Enumeration
  #Timer_A
  #Timer_C
EndEnumeration

If OpenWindow(0, 0, 0, 222, 50, "Timer", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  CreateGadgetList(WindowID(0))
  
  ButtonGadget(0, 10, 10, 200, 30, "Timer", #PB_Button_Toggle)
  
  CreateTimer(#Timer_A, 0, 6, 2000)
  CreateTimer(#Timer_C, 0, 2, 1500)
  
  Repeat
    
    Event = WaitWindowEvent()
    
    If Event = #PB_Event_Gadget
      
      If GetGadgetState(0)
        Timer = CreateTimer(#PB_Any, 0, 1, 1000)
      Else
        FreeTimer(Timer)
      EndIf
      
    ElseIf Event = #PB_Event_Timer
      
      Select EventTimer()
        Case #Timer_A
          Debug "#Timer_A"
          
        Case #Timer_C
          Debug "#Timer_C"
          
        Case Timer
          Debug "Timer"
          
      EndSelect
      
    EndIf
    
  Until Event = #PB_Event_CloseWindow
EndIf
Dri ;)

Publié : mar. 20/juin/2006 10:10
par Flype
intéressant Dr Dri, va falloir déchiffrer tout çà mais merci.
je pense que çà va me servir justement pour le projet #1 (SQL).
:P

Publié : mer. 21/juin/2006 16:35
par Dr. Dri
Une version light, j'ai gardé l'essentiel

Code : Tout sélectionner

Prototype   PB_Object_GetOrAllocate   (Objects, Object.l)
Prototype   PB_Object_GetObject       (Objects, Object.l)
Prototype   PB_Object_IsObject        (Objects, Object.l)
Prototype   PB_Object_EnumerateAll    (Objects, ObjectEnumerateAllCallback, *VoidData)
Prototype   PB_Object_EnumerateStart  (Objects)
Prototype   PB_Object_EnumerateNext   (Objects, *Object.Long)
Prototype   PB_Object_EnumerateAbort  (Objects)
Prototype   PB_Object_Free            (Objects, Object.l)
Prototype.l PB_Object_Init            (StructureSize.l, IncrementStep.l, ObjectFreeFunction)
Prototype   PB_Object_GetThreadMemory (MemoryID.l)
Prototype.l PB_Object_InitThreadMemory(Size.l, InitFunction, EndFunction)

Global Object_GetOrAllocate   .PB_Object_GetOrAllocate
Global Object_GetObject       .PB_Object_GetObject
Global Object_IsObject        .PB_Object_IsObject
Global Object_EnumerateAll    .PB_Object_EnumerateAll
Global Object_EnumerateStart  .PB_Object_EnumerateStart
Global Object_EnumerateNext   .PB_Object_EnumerateNext
Global Object_EnumerateAbort  .PB_Object_EnumerateAbort
Global Object_Free            .PB_Object_Free
Global Object_Init            .PB_Object_Init
Global Object_GetThreadMemory .PB_Object_GetThreadMemory
Global Object_InitThreadMemory.PB_Object_InitThreadMemory

!extrn _PB_Object_GetOrAllocateID@8
!extrn _PB_Object_GetObject@8
!extrn _PB_Object_IsObject@8
!extrn _PB_Object_EnumerateAll@12
!extrn _PB_Object_EnumerateStart@4
!extrn _PB_Object_EnumerateNext@8
!extrn _PB_Object_EnumerateAbort@4
!extrn _PB_Object_FreeID@8
!extrn _PB_Object_Init@12
!extrn _PB_Object_GetThreadMemory@4
!extrn _PB_Object_InitThreadMemory@12

!MOV [v_Object_GetOrAllocate]   , _PB_Object_GetOrAllocateID@8
!MOV [v_Object_GetObject]       , _PB_Object_GetObject@8
!MOV [v_Object_IsObject]        , _PB_Object_IsObject@8
!MOV [v_Object_EnumerateAll]    , _PB_Object_EnumerateAll@12
!MOV [v_Object_EnumerateStart]  , _PB_Object_EnumerateStart@4
!MOV [v_Object_EnumerateNext]   , _PB_Object_EnumerateNext@8
!MOV [v_Object_EnumerateAbort]  , _PB_Object_EnumerateAbort@4
!MOV [v_Object_Free]            , _PB_Object_FreeID@8
!MOV [v_Object_Init]            , _PB_Object_Init@12
!MOV [v_Object_GetThreadMemory] , _PB_Object_GetThreadMemory@4
!MOV [v_Object_InitThreadMemory], _PB_Object_InitThreadMemory@12
Dri

Publié : mer. 21/juin/2006 18:10
par Flype
merci c'est cool.

tu sais pas pourquoi çà marche pas dans jaPBe par hasard ?

Compilateur:
POLINK: fatal error: 11 unresolved external(s)

Publié : mer. 21/juin/2006 18:20
par Dr. Dri
Franchement je n'en sais rien, comme ce sont les symboles externes (en gros les adresses des fonctions) peut être qu'avec jaPBe il faut virer les arguments (en gros vire tous les @ et ce qui va apres)

Dri :-?

Publié : mer. 21/juin/2006 19:01
par Flype
pas çà, je vais demander à gnozal.

Publié : jeu. 22/juin/2006 15:54
par gnozal
Flype a écrit :pas çà, je vais demander à gnozal.
C'est un bug Purebasic.
Si je fais la même chose à la main (identique à ce que fait jaPBe) :
> PBCompiler PB_EditorOutput.pb
******************************************
PureBasic v4.00 (Windows - x86)
******************************************

Compiling pb_editoroutput.pb
Loading external libraries...
Starting compilation...
Including source: C:\Purebasic400\Compilers\PB_EditorOutput2.pb
59 lines processed.
Creating executable.
Error: Linker
POLINK: error: Unresolved external symbol '_PB_Object_GetOrAllocateID'.
POLINK: error: Unresolved external symbol '_PB_Object_GetObject'.
POLINK: error: Unresolved external symbol '_PB_Object_IsObject'.
POLINK: error: Unresolved external symbol '_PB_Object_EnumerateAll'.
POLINK: error: Unresolved external symbol '_PB_Object_EnumerateStart'.
POLINK: error: Unresolved external symbol '_PB_Object_EnumerateNext'.
POLINK: error: Unresolved external symbol '_PB_Object_EnumerateAbort'.
POLINK: error: Unresolved external symbol '_PB_Object_FreeID'.
POLINK: error: Unresolved external symbol '_PB_Object_Init'.
POLINK: error: Unresolved external symbol '_PB_Object_GetThreadMemory'.
POLINK: error: Unresolved external symbol '_PB_Object_InitThreadMemory'.
POLINK: fatal error: 11 unresolved external(s).

C:\PureBasic400\Compilers>
Avec PB_EditorOutput.pb

Code : Tout sélectionner

#jaPBe_CompilerVersion="4.00"
#jaPBe_IsDebuggerRunning=0
#jaPBe_IsExecute=0
#jaPBe_ExecuteBuild=1
#jaPBe_ExecuteType=0
#jaPBe_OnError=0
#jaPBe_SourcePath=""
#jaPBe_SourceFile=""
IncludePath "C:\PUREBASIC400\JAPBE\Include"
IncludePath ""
IncludeFile "C:\Purebasic400\Compilers\PB_EditorOutput2.pb"
Et PB_EditorOutput2.pb

Code : Tout sélectionner

Prototype   PB_Object_GetOrAllocate   (Objects, Object.l) 
Prototype   PB_Object_GetObject       (Objects, Object.l) 
Prototype   PB_Object_IsObject        (Objects, Object.l) 
Prototype   PB_Object_EnumerateAll    (Objects, ObjectEnumerateAllCallback, *VoidData) 
Prototype   PB_Object_EnumerateStart  (Objects) 
Prototype   PB_Object_EnumerateNext   (Objects, *Object.Long) 
Prototype   PB_Object_EnumerateAbort  (Objects) 
Prototype   PB_Object_Free            (Objects, Object.l) 
Prototype.l PB_Object_Init            (StructureSize.l, IncrementStep.l, ObjectFreeFunction) 
Prototype   PB_Object_GetThreadMemory (MemoryID.l) 
Prototype.l PB_Object_InitThreadMemory(Size.l, InitFunction, EndFunction) 

Global Object_GetOrAllocate   .PB_Object_GetOrAllocate 
Global Object_GetObject       .PB_Object_GetObject 
Global Object_IsObject        .PB_Object_IsObject 
Global Object_EnumerateAll    .PB_Object_EnumerateAll 
Global Object_EnumerateStart  .PB_Object_EnumerateStart 
Global Object_EnumerateNext   .PB_Object_EnumerateNext 
Global Object_EnumerateAbort  .PB_Object_EnumerateAbort 
Global Object_Free            .PB_Object_Free 
Global Object_Init            .PB_Object_Init 
Global Object_GetThreadMemory .PB_Object_GetThreadMemory 
Global Object_InitThreadMemory.PB_Object_InitThreadMemory 

!EXTRN _PB_Object_GetOrAllocateID@8 
!EXTRN _PB_Object_GetObject@8 
!EXTRN _PB_Object_IsObject@8 
!EXTRN _PB_Object_EnumerateAll@12 
!EXTRN _PB_Object_EnumerateStart@4 
!EXTRN _PB_Object_EnumerateNext@8 
!EXTRN _PB_Object_EnumerateAbort@4 
!EXTRN _PB_Object_FreeID@8 
!EXTRN _PB_Object_Init@12 
!EXTRN _PB_Object_GetThreadMemory@4 
!EXTRN _PB_Object_InitThreadMemory@12 

!MOV [v_Object_GetOrAllocate]   , _PB_Object_GetOrAllocateID@8 
!MOV [v_Object_GetObject]       , _PB_Object_GetObject@8 
!MOV [v_Object_IsObject]        , _PB_Object_IsObject@8 
!MOV [v_Object_EnumerateAll]    , _PB_Object_EnumerateAll@12 
!MOV [v_Object_EnumerateStart]  , _PB_Object_EnumerateStart@4 
!MOV [v_Object_EnumerateNext]   , _PB_Object_EnumerateNext@8 
!MOV [v_Object_EnumerateAbort]  , _PB_Object_EnumerateAbort@4 
!MOV [v_Object_Free]            , _PB_Object_FreeID@8 
!MOV [v_Object_Init]            , _PB_Object_Init@12 
!MOV [v_Object_GetThreadMemory] , _PB_Object_GetThreadMemory@4 
!MOV [v_Object_InitThreadMemory], _PB_Object_InitThreadMemory@12 
Probablement un bug avec INCLUDEFILE ?

Publié : jeu. 22/juin/2006 18:20
par poshu
Bon, j'ai grosso modo fini par capter et appliquer le concept.

D'un point de vu threadsafe, tu peux nous en dire plus?

Publié : jeu. 22/juin/2006 18:26
par Dr. Dri
Tu as mis le doigt sur les deux fonctions que je ne sais pas utiliser... Pour la simple raison que je n'ai pas trouvé d'exemple dans le SDK, et parce qu'elles ne demandent pas de liste d'objets comme premier argument.

Dri :oops:

Publié : jeu. 22/juin/2006 18:31
par poshu
Zut, en tous cas merci d'avoir maché le travail pour nous.

Fred? Help?

Publié : ven. 23/juin/2006 14:19
par Flype
salut dri,

Bon j'ai réussi à implémenter (en partie) les objets pour le projet #1.

Par contre, j'aurai quand même qq questions...

Quand j'écris çà, pour initialiser l'objet database :

DatabaseObjects.l = Object_Init(SizeOf(THIS), 1, @_CloseDatabase())

pourquoi la fonction _CloseDatabase() est-elle réellement appelée dès le début du source ?

et à l'inverse, à la fin du programme, alors que je m'attendais à ce que la fonction soit appelée automatiquement si l'utilisateur n'a lui-même fait CloseDatabase(), elle n'est pas appelée du tout...


[EDIT]
bon j'ai compris pourquoi la fonction _CloseDatabase() est appelée au début du source, puisque c'est Object_GetOrAllocate() qui l'appelle pour réinitialiser/réallouer l'objet/identifiant.

par contre, pour la libération automatique des objets en fin de source, j'ai dû louper un étage...

Publié : ven. 23/juin/2006 15:51
par Dr. Dri
je viens de tester et effectivement PB ne semble pas appeller la fonction à la fermeture du programme.

dans ce cas est-ce que dans une lib on peut définir une fonction automatiquement appellée au début et une autre a la fin ?

Dri

Publié : ven. 23/juin/2006 15:59
par Flype
that is the question !

par contre de toutes facons avec tailbite, c'est possible (voir dans le chm) :

Code : Tout sélectionner

   ProcedureDLL MyLib_Init()
     ; Do some initializing stuff, allocate memory, etc.
   EndProcedure

   ProcedureDLL MyLib_End()
     ; Do some cleaning, free memory, unload third party DLLs, etc.
   EndProcedure
donc en principe grace à Object_EnumerateAll() on devrait pouvoir s'en sortir. mais comment Fred ferait en C/C++

Publié : sam. 24/juin/2006 0:27
par Flype
çà remarche dans jaPBe si la constante #jaPBe_SourcePath est défini sur le bon dossier.

Publié : lun. 26/juin/2006 21:29
par poshu
Euh... Ca plante chez moi, meme avec l'IDE de pure, si je coupe le debugger et donc si je crée un executable :/