ISAWHIM
28-10-2008, 05:09
CALLBACKS were created to help stop programs from hogging resources using endless loops to check for input and control states. Like a wake-up call, you tell windows to give you a ring when you need to wake-up and do something. (Respond to a mouse-move, button-click, window-resize, etc...)
A side-trait of a CALLBACK, was the creation of a dynamic associative handle/class. This turns anything that you can create with a handle, into a potential clone. This works much like a TYPE string. Each item with a handle becomes a virtual new element, handled by windows assigning a second handle to every element.
MyWindow (Handle: 12345) becomes...
MyWindow.(CallHandle: 87654)
MyWindow.(CallHandle: 19843)
MyWindow.(CallHandle: 65430)
Each window having the same set of code, and sharing the same controls. You don't have to define 1000 separate buttons for 1000 windows. Only ONE constant is needed for the single "Clone" window.
MyWindow (Handle: 12345)
- Button (%btnCONSTANT = 1)
becomes...
MyWindow.(CallHandle: 87654)
- Button.(CallHandle: 87654)
MyWindow.(CallHandle: 19843)
- Button.(CallHandle: 19843)
MyWindow.(CallHandle: 65430)
- Button.(CallHandle: 65430)
To see this in action, you can use a neat TOOL called a "Window-Analyzer" which shows the hWnd and the call-hWnd, child/parent levels, and even the ID constants. (Great for debugging if you are using constants that you "Think" are unique, but they are actually overlapping, causing "Issues".)
The "ANALYZER" link is the one you want.
http://allapi.mentalis.org/vbexamples/list.php?category=MISC
The "ApiViewer" and "API-Guide" are good resources also. (The samples are VB6, but it is the order of use, and constants which are important to notice. CALLBACKS being a new feature, will undoubtedly keep you waiting for new features to be developed. This will allow you to develop your own features to add, without having to wait.)
This comes in handy, for instance in a "Paint Program". Each new window holds an image, edit controls, menu's, more dialogs, buttons... You are unsure if a user will have 10 or 10,000 windows open. (That would make you mad, attempting to hand-code all those controls and constants and IF...THEN and WHILE...END and SELECT CASE statements.)
This is where a little "New" thinking has to come into play.
There is only ONE window/dialog which you NEED to code manually for full display. This MAIN APPLICATION window/dialog, MUST be created and SHOWN with a CALLBACK attached, before any other controls or dialogs are created. This MAIN APPLICATION will hold the critical (HANDLE) hWnd that your program needs for any CALLBACKS.
You can define child elements for the MAIN APPLICATION before you SHOW the window/dialog, but ONLY if those elements will not have a CALLBACK themselves. Since they are children-of-a-parent, and the parent-handle has not been SHOWN, with the CALLBACK... there is no way to create a CALLBACK for a child of a parent which does not exist at the moment. (It exists as a HANDLE, but not as a CALLBACK HANDLE.)
This is why they created the first element of a callback called a notification. There is an order to creating these CALLBACK clones.
1. WM_PARENTNOTIFY: (Prior to creation, the parent is alerted of the creation.)
This can be used to suppress, or make adjustments in memory/variables/code, prior to creation.
2. WM_CREATE: (When you request to CREATE a window/dialog/button/element.)
Creation notice comes post creation, and prior to display. Values can be set here, and display can be suppressed.
3. WM_INITDIALOG: (Since these "Windows" are "Dialog Windows", the next event is this one.)
This is where you create your controls/elements for display. The next notice will be "SHOW".
4. WM_SHOWWINDOW: (Everything is now visible, ready for use, and you now have a MAIN WINDOW.)
In this specific case, the PARENT of MAIN WINDOW is "WINDOWS 98/ME/NT/2K/XP/LH/VISTA".
This window now has TWO handles. The TB handle for the "Original Control/Dialog", plus the "Call-Handle" for this "Virtual Window". TB only suggests what the window will look like. Windows adopts full control of this "Virtual Window" and all elements created for display from this point on, which are created as a child to this window. (This will not include any DIRECT displayed or created controls that are not a child of this hWnd. EG, Creating a new dialog who is a child of "0", will be a full TB control window, until you assign that element to a CALLBACK.)
Following me here?
Quick review...
1. Create Dialog in TB, (Only the dialog), and send that info to a CALLBACK creation. "CALL MyCallbackProc()"
2. That window becomes cloned, and the "Notices" in the callback are used to setup the clone.
3. Each CALL HANDLE will step through an order of notices until the clone-dialog is displayed.
4. At the WM_INITDIALOG notice, just before the WM_SHOWWINDOW notice, the controls should be setup.
5. Use the program... Handle other calls as needed...
6. Now we have to exit...
Exit... Exit what? Well, there is no "Real Window" so you can't exit the normal way. You have to "Kill" the clone. Sounds like a neat game or movie, but it is just another function. At the moment, this can only be done with API code. Or with the SYSMENU-CLOSE button, if one exits on your window that you created.
The procedure to close a window is similar to the way it opens.
1. Something tells "Windows", your clone-creator, that you want to exit. "SendMessage(hWnd, %WM_SYSCOMMAND, %SC_CLOSE, 0)"
2. This CALL triggers the CALLBACK notice, "%WM_SYSCOMMAND, %SC_CLOSE". There should be code here to handle YES/NO or SAVE, etc... This event is followed by "%WM_CLOSE", which is where you may want to destroy elements or free memory before you actually exit. (NOTE: Look below to see the API call to destroy.)
3. Once that is finished, the window may trigger a %WM_SHOWWINDOW, as it disappears from the screen, but that is not a solid state notice, just a side-path that MAY happen.
4. The last notice before complete destruction is, "%WM_DESTROY". This sends a message to all children, and tells them to destroy also. It should be assumed they all still exist at this point.
5. Wait... There is one more notice... But this goes to the PARENT of this window, (Which is "Windows".) "%WM_NCDESTROY", tells the PARENT of this window, that all the children of the clone and the child-clone are all killed, and memory can be released.
Sounds like a breeze!
Here is the missing "Destroy" code. (Missing as of, 10/27/08)
Declare Function DestroyWindow _
Lib "user32.dll" _
ALIAS "DestroyWindow" _
(ByVal hWnd As Long) As Long
' -- In the "%WM_CLOSE" area where notices are handled... Add this line...
DestroyWindow(CBHNDL)
Full sample-code to follow...
A side-trait of a CALLBACK, was the creation of a dynamic associative handle/class. This turns anything that you can create with a handle, into a potential clone. This works much like a TYPE string. Each item with a handle becomes a virtual new element, handled by windows assigning a second handle to every element.
MyWindow (Handle: 12345) becomes...
MyWindow.(CallHandle: 87654)
MyWindow.(CallHandle: 19843)
MyWindow.(CallHandle: 65430)
Each window having the same set of code, and sharing the same controls. You don't have to define 1000 separate buttons for 1000 windows. Only ONE constant is needed for the single "Clone" window.
MyWindow (Handle: 12345)
- Button (%btnCONSTANT = 1)
becomes...
MyWindow.(CallHandle: 87654)
- Button.(CallHandle: 87654)
MyWindow.(CallHandle: 19843)
- Button.(CallHandle: 19843)
MyWindow.(CallHandle: 65430)
- Button.(CallHandle: 65430)
To see this in action, you can use a neat TOOL called a "Window-Analyzer" which shows the hWnd and the call-hWnd, child/parent levels, and even the ID constants. (Great for debugging if you are using constants that you "Think" are unique, but they are actually overlapping, causing "Issues".)
The "ANALYZER" link is the one you want.
http://allapi.mentalis.org/vbexamples/list.php?category=MISC
The "ApiViewer" and "API-Guide" are good resources also. (The samples are VB6, but it is the order of use, and constants which are important to notice. CALLBACKS being a new feature, will undoubtedly keep you waiting for new features to be developed. This will allow you to develop your own features to add, without having to wait.)
This comes in handy, for instance in a "Paint Program". Each new window holds an image, edit controls, menu's, more dialogs, buttons... You are unsure if a user will have 10 or 10,000 windows open. (That would make you mad, attempting to hand-code all those controls and constants and IF...THEN and WHILE...END and SELECT CASE statements.)
This is where a little "New" thinking has to come into play.
There is only ONE window/dialog which you NEED to code manually for full display. This MAIN APPLICATION window/dialog, MUST be created and SHOWN with a CALLBACK attached, before any other controls or dialogs are created. This MAIN APPLICATION will hold the critical (HANDLE) hWnd that your program needs for any CALLBACKS.
You can define child elements for the MAIN APPLICATION before you SHOW the window/dialog, but ONLY if those elements will not have a CALLBACK themselves. Since they are children-of-a-parent, and the parent-handle has not been SHOWN, with the CALLBACK... there is no way to create a CALLBACK for a child of a parent which does not exist at the moment. (It exists as a HANDLE, but not as a CALLBACK HANDLE.)
This is why they created the first element of a callback called a notification. There is an order to creating these CALLBACK clones.
1. WM_PARENTNOTIFY: (Prior to creation, the parent is alerted of the creation.)
This can be used to suppress, or make adjustments in memory/variables/code, prior to creation.
2. WM_CREATE: (When you request to CREATE a window/dialog/button/element.)
Creation notice comes post creation, and prior to display. Values can be set here, and display can be suppressed.
3. WM_INITDIALOG: (Since these "Windows" are "Dialog Windows", the next event is this one.)
This is where you create your controls/elements for display. The next notice will be "SHOW".
4. WM_SHOWWINDOW: (Everything is now visible, ready for use, and you now have a MAIN WINDOW.)
In this specific case, the PARENT of MAIN WINDOW is "WINDOWS 98/ME/NT/2K/XP/LH/VISTA".
This window now has TWO handles. The TB handle for the "Original Control/Dialog", plus the "Call-Handle" for this "Virtual Window". TB only suggests what the window will look like. Windows adopts full control of this "Virtual Window" and all elements created for display from this point on, which are created as a child to this window. (This will not include any DIRECT displayed or created controls that are not a child of this hWnd. EG, Creating a new dialog who is a child of "0", will be a full TB control window, until you assign that element to a CALLBACK.)
Following me here?
Quick review...
1. Create Dialog in TB, (Only the dialog), and send that info to a CALLBACK creation. "CALL MyCallbackProc()"
2. That window becomes cloned, and the "Notices" in the callback are used to setup the clone.
3. Each CALL HANDLE will step through an order of notices until the clone-dialog is displayed.
4. At the WM_INITDIALOG notice, just before the WM_SHOWWINDOW notice, the controls should be setup.
5. Use the program... Handle other calls as needed...
6. Now we have to exit...
Exit... Exit what? Well, there is no "Real Window" so you can't exit the normal way. You have to "Kill" the clone. Sounds like a neat game or movie, but it is just another function. At the moment, this can only be done with API code. Or with the SYSMENU-CLOSE button, if one exits on your window that you created.
The procedure to close a window is similar to the way it opens.
1. Something tells "Windows", your clone-creator, that you want to exit. "SendMessage(hWnd, %WM_SYSCOMMAND, %SC_CLOSE, 0)"
2. This CALL triggers the CALLBACK notice, "%WM_SYSCOMMAND, %SC_CLOSE". There should be code here to handle YES/NO or SAVE, etc... This event is followed by "%WM_CLOSE", which is where you may want to destroy elements or free memory before you actually exit. (NOTE: Look below to see the API call to destroy.)
3. Once that is finished, the window may trigger a %WM_SHOWWINDOW, as it disappears from the screen, but that is not a solid state notice, just a side-path that MAY happen.
4. The last notice before complete destruction is, "%WM_DESTROY". This sends a message to all children, and tells them to destroy also. It should be assumed they all still exist at this point.
5. Wait... There is one more notice... But this goes to the PARENT of this window, (Which is "Windows".) "%WM_NCDESTROY", tells the PARENT of this window, that all the children of the clone and the child-clone are all killed, and memory can be released.
Sounds like a breeze!
Here is the missing "Destroy" code. (Missing as of, 10/27/08)
Declare Function DestroyWindow _
Lib "user32.dll" _
ALIAS "DestroyWindow" _
(ByVal hWnd As Long) As Long
' -- In the "%WM_CLOSE" area where notices are handled... Add this line...
DestroyWindow(CBHNDL)
Full sample-code to follow...