| 
			
				|  | Cheat Engine The Official Site of Cheat Engine
 
 
 |  
 
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| ParkourPenguin I post too much
 
  Reputation: 152 
 Joined: 06 Jul 2014
 Posts: 4706
 
 
 | 
			
				|  Posted: Sat Sep 21, 2024 3:02 pm    Post subject: |   |  
				| 
 |  
				| registerFormAddNotification gets called for every form that gets newly created. If you don't know what it does, play around with it and see what happens: 
 Execute this then open a bunch of windows in CE. e.g. a structure dissect window 	  | Code: |  	  | registerFormAddNotification(function(f) print(f.ClassName)
 end)
 
 | 
 
 The first part of that code I stole and modified from DB's post is a helper function:
 
 The function's name, "forEachAndFutureForm", describes what it does. It takes two parameters: a class name and a function that takes a form. The provided function will be executed once for every form with the specified class name- both currently visible forms and any forms that get created in the future. 	  | Code: |  	  | function forEachAndFutureForm(classname, func) local i
 for i=0,getFormCount()-1 do
 local f = getForm(i)
 if f.ClassName==classname then
 func(f)
 end
 end
 
 registerFormAddNotification(function(f)
 if classname==f.ClassName then
 f.registerFirstShowCallback(func)
 end
 end)
 end
 | 
 The for loop iterates over the currently visible forms and executes the function for each form that already exists.
 The call to `registerFormAddNotification` will make sure CE calls the provided function whenever a new form is created. `registerFirstShowCallback` makes sure everything in the form has been initialized before the function gets called- e.g. the popup menu might not exist when the `registerFormAddNotification` callback is executed, but it will when the `registerFirstShowCallback` callback is executed.
 
 The second part calls that helper function:
 
 The class name of the form you want to modify is "TfrmStructures2". The callback function takes the form and adds a new item to the popup menu. 	  | Code: |  	  | forEachAndFutureForm('TfrmStructures2',function(f) local mi = createMenuItem(f.pmStructureView)
 mi.Name = 'miHelloWorld'
 mi.Caption = 'Hello'
 mi.OnClick = function() print'Hello' end
 
 f.pmStructureView.Items.add(mi)
 end)
 | 
 
 You can probably figure out the class name by opening the window and iterating over all the current forms:
 
  	  | Code: |  	  | for i = 0, getFormCount() - 1 do print(getForm(i).ClassName)
 end
 | 
 To get the name of the popup menu, iterate over all the owned components of the form:
 
  	  | Code: |  	  | local structfrm for i = 0, getFormCount() - 1 do
 local f = getForm(i)
 if f.ClassName == 'TfrmStructures2' then
 structfrm = f
 break
 end
 end
 
 for i = 0, structfrm.ComponentCount - 1 do
 local c = structfrm.Component[i]
 print(c.ClassName, '\t', c.Name, '\t', c.Caption)
 end
 | 
 If you have CE's source code readily available, it might be faster to look in the relevant lfm file. e.g. Cheat Engine/StructuresFrm2.lfm:
 
  	  | Code: |  	  | object frmStructures2: TfrmStructures2 ...
 object pmStructureView: TPopupMenu
 Images = sdImageList
 OnPopup = pmStructureViewPopup
 Left = 48
 Top = 120
 object miChangeValue: TMenuItem
 Caption = 'Change value'
 ImageIndex = 5
 ShortCut = 13
 OnClick = miChangeValueClick
 end
 ...
 | 
 _________________
 
 I don't know where I'm going, but I'll figure it out when I get there. |  |  
		| Back to top |  |  
		|  |  
		| Csimbi I post too much
 
  Reputation: 97 
 Joined: 14 Jul 2007
 Posts: 3327
 
 
 | 
			
				|  Posted: Sun Sep 22, 2024 8:50 am    Post subject: |   |  
				| 
 |  
				|  	  | ParkourPenguin wrote: |  	  | ... | 
 Thanks for the detailed explanation.
 
 Let me check if I got this right:
 - that timer-based registration I posted earlier was the wrong way to go.
 - the right way to go is forEachAndFutureForm because that event will fire every time a new instance of a form is created.
 - forEachAndFutureForm must interate through all forms and call the function passed as a parameter when the right form is found (which, in my case is fn_AddPopupMenuItems).
 
 Questions (please forgive my ignorance again):
 - Why do I have to scan all forms using forEachAndFutureForm and re-register each form? Won't that cause issues in the long run without unregistering potentially existing registrations?
 - What happens when another script includes forEachAndFutureForm for the same form, albeit with a different function?
 - Wouldn't it be more logical to have a PostCreate() event that fires once for every new instance of the form, after it has been instantiated and fully initialized just before it would be displayed?
 |  |  
		| Back to top |  |  
		|  |  
		| ParkourPenguin I post too much
 
  Reputation: 152 
 Joined: 06 Jul 2014
 Posts: 4706
 
 
 | 
			
				|  Posted: Sun Sep 22, 2024 9:57 am    Post subject: |   |  
				| 
 |  
				| `forEachAndFutureForm` is just a helper function DB made up. You can call it whatever you want. The important bits are CE's API- particularly `registerFormAddNotification` and `registerFirstShowCallback`. 	  | Csimbi wrote: |  	  | the right way to go is forEachAndFutureForm because that event will fire every time a new instance of a form is created | 
 
 
 `registerFormAddNotification` only triggers for new forms. It doesn't trigger for forms that already exist. e.g. if you already had a structure dissect window open and execute that code without the `for` loop, any new structure dissect windows would be modified, but the one that was already opened wouldn't. 	  | Csimbi wrote: |  	  | Why do I have to scan all forms using forEachAndFutureForm and re-register each form? Won't that cause issues in the long run without unregistering potentially existing registrations? | 
 
 I'm not sure what you mean by "re-register each form". If you call that function more than once, then the old `registerFormAddNotification` callback(s) will still be run. You can modify the function a little to be able to unregister it:
 
 Try modifying the message printed and execute the script again. 	  | Code: |  	  | function forEachAndFutureForm(classname, func) for i=0,getFormCount()-1 do
 local f = getForm(i)
 if f.ClassName==classname then
 func(f)
 end
 end
 
 return registerFormAddNotification(function(f)
 if classname==f.ClassName then
 f.registerFirstShowCallback(func)
 end
 end)
 end
 
 if structDissectPrintHelloCallback then
 unregisterFormAddNotification(structDissectPrintHelloCallback)
 structDissectPrintHelloCallback = nil
 end
 
 structDissectPrintHelloCallback = forEachAndFutureForm('TfrmStructures2', function(f)
 if f.pmStructureView.miHelloWorld then
 -- might run again if any windows are opened
 f.pmStructureView.miHelloWorld.destroy()
 end
 
 local mi = createMenuItem(f.pmStructureView)
 mi.Name = 'miHelloWorld'
 mi.Caption = 'Hello'
 mi.OnClick = function() print'Hello' end
 
 f.pmStructureView.Items.add(mi)
 end)
 | 
 NB: when this code is run multiple times, the `for` loop might execute your function on a window that a previous callback had already run on. This is why this callback now destroys the menu item created by any previous callback.
 
 
 Both of the callback functions get run. 	  | Csimbi wrote: |  	  | What happens when another script includes forEachAndFutureForm for the same form, albeit with a different function? | 
 Again, it's fine to play around with Lua yourself and see what happens:
 
  	  | Code: |  	  | ... forEachAndFutureForm('TfrmStructures2', function(f)
 print'Hello'
 end)
 forEachAndFutureForm('TfrmStructures2', function(f)
 print'World'
 end)
 | 
 
 That's exactly what `registerFirstShowCallback` is. It registers a callback function to be run when the form is first shown. This is better than setting a single callback function for an event (e.g. Timer.OnTimer) because several different functions can be registered without overriding each other (see previous code block). 	  | Csimbi wrote: |  	  | Wouldn't it be more logical to have a PostCreate() event that fires once for every new instance of the form, after it has been instantiated and fully initialized just before it would be displayed? | 
 _________________
 
 I don't know where I'm going, but I'll figure it out when I get there. |  |  
		| Back to top |  |  
		|  |  
		|  |  
  
	| 
 
 | You cannot post new topics in this forum You cannot reply to topics in this forum
 You cannot edit your posts in this forum
 You cannot delete your posts in this forum
 You cannot vote in polls in this forum
 You cannot attach files in this forum
 You can download files in this forum
 
 |  |