09-11-2009 10:34 AM
Why does calling InstallWinMsgCallback change the callback data of my panel? This does not seem like proper behavior? Based on the documentation, I don't get the impression that my panel's ATTR_CALLBACK_DATA and the callbackdata pointer passed to InstallWinMsgCallback have to be the same... but they do.
This problem can be reproduced easily. Set the a panel's ATTR_CALLBACK_DATA, call InstallWinMsgCallback with something different and they then look at/try to use what you get back from GetPanelAttribute( ...,ATTR_CALLBACK_DATA ..);
If this is intended behavior it makes InstallWinMsgCallback quite limited. We currently have some libraries that add things like StatusBars, Docking, etc to UI and these libraries use InstallWinMsgCallback. I can't use them in apps that need to use a panel's ATTR_CALLBACK_DATA.
(I'm using CVI 9.0.0)
Greg
Solved! Go to Solution.
09-11-2009 01:52 PM
Hey Greg,
You've run into an unfortunate consequence of the way that we chain callbacks for the implementation of InstallWinMsgCallback, as well as other toolbox functions such as ChainPanelCallback. The solution for your situation is to use the functions SetChainedPanelCallbackData and GetChainedPanelCallbackData. This will allow you to be able to set and get the callback data associated with both callback routines.
Feel free to let me know if you have any further questions about this.
NickB
National Instruments
09-11-2009 02:13 PM
Quite unfortunate and should be explicitly indicated in the InstallWinMsgCallback documentation.
Using ChainPanelCallback would imply that I know/assume my panel may get 'chained' at some point, but this not the case. Consider that fact the most applications I develop make heavy use of libraries built to enhance and add functionality to CVI UI controls. In order to use a panel's ATTR_CALLBACK_DATA, (which I do in almost every application/library I write to eliminate the need for global panel variables (and other things), I have to know that none of the libraries/helper code, I use calls 'InstallWinMsgCallback'.... or assume they do and work around it.
Without knowing how you've Implemented InstallWinMsgCallback, it doesn't seem like a difficult task to leave the panel's callback data alone. It is a poor design that the callback data gets altered by what should a 'hidden' feature to the standard callback implementation.
Are there plans to fix/improve this behavior in the CVI 2009?
Greg
09-11-2009 05:32 PM
09-14-2009 08:44 AM
Here is how I run into this problem..
In many of my applications I set the Panel ATTR_CALLBACK_DATA to a reference to a structure of "application settings". In all my CTRL callbacks I call "GetPanelAttribute.. ATTR_CALLBACK_DATA to get this reference. I often use multiple 'instances" of the same code/objects/(dlls) and this method is an easy way to eliminate all global variables (such as the default-to-global panel handle).
This I can't do after InstallWinMsgCallback is called and I couldn't find any reason in the docs as to why/how my panel callback data was changed. I consider this a pretty normal thing to do which is why I'm making a case for it to be 'fixed'. Essentially what this means is that GetPanelAttribute(...ATTR_CALLBACK_DATA..) is completely unreliable in applications that depend on other code/libraries or in which I don't have 100% control over all of the code, since I cannot be certain that the included code doesn't InstallWinMsgCallback. The only way to reliably get a panel's callback data is with the Get/SetChainedPanelCallbackData?
Greg
09-14-2009 09:10 AM
Hey Greg,
Thanks for that explanation. It makes sense, and I can certainly understand how this would be a major headache to you. Just curious - is there a reason you don't set the control's callback data to be a reference to the same application settings structure? I assume you are probably using it for something else?
As far as you second point is concerned, I definitely agree that the documentation needs work in this area, and I will be getting this pushed through in coming versions. I'm thankful for you pointing out this deficiency in our documentation.
Finally, if you are using some other code / libraries that you suspect might be chaining callbacks or using functions like InstallWinMsgCallback, I would recommend using Get/SetChainedPanelCallbackData. There is very little overhead involved in making these calls (It basically loops backwards through the callback chain to find the original callback function and data - so the overhead is proportional to the number of callbacks that have been chained. From what I can tell, in your case, this should just be one extra loop iteration), and it is guaranteed to give you the original callback data associated with the panel.
NickB
National Instruments
09-14-2009 09:31 AM
Nick,
You are correct in that some cases I am using the Ctrl's callback data for something else and also, I am too lazy to want to have to set the callback data for each of the dozens of controls on some panels. I agree that there are several ways to work around this problem. I guess my point is that they should not be necessary. My original question stands as to way this must be so since it doesn't seem like a difficult fix and when fixed would make a more logical and clean solution i.e. ChainCallbacks do their own thing without messing with the default behavior / normal callback functions/data.
I have this particular application working fine with the Chained callbacks. (another minor annoyance.. I didn't have a panel callback function to chain.. so had to make an empty one)
Thanks for the help/info.
Greg
09-14-2009 10:03 AM
Hey Greg,
It sounds like you've gotten things working, so I apologize about dragging this out, but I wanted to make sure I understand your mentioned minor annoyance. You said that you had to create an empty callback function to chain - you should not have to do this. If you are referring to using the GetChainedPanelCallbackData to get the original callback data, you just need to pass an empty string to the "type name" parameter. This is another thing that isn't documented very well - and one that I will be specifically working to address. I most likely muddied the waters by including SetChainedPanelCallbackData in the converstation. You would only need to use this function if you needed to set new callback data after the call to InstallWinMsgCallback, or a call to one of the other callback chaining functions. If you ever run into this case (needing to change the original callback data after you fear the callback data may have been altered by a callback chaining function), you would call SetChainedPanelCallbackData with an empty string as the "type name" parameter.
I will do my best to answer your question regarding why the behavior is the way it is as well. The main problem is that the Get/SetPanelAttribute functions are part of our UI library, and the InstallWinMsgCallback / callback chaining functions are part of our toolbox code. Initially, the toolbox code was developed more as an example of some of the things you could do with CVI, but as it has grown, more and more dependence on it has been established, and the line between example code (that was never necessarily intended to be as robust as our libraries) and library code has been blurred.
This means that the callback chaining functions are in no way integrated with our UI Library code. In fact, if you open up toolbox.c, you can find all the implementation for these functions. Basically, what happens is when these functions are called, we get the current callback data and callback function (using GetPanelAttribute), store these items in a list, and then set the new callback function and data with the UI Library SetPanelAttribute function. When events need to be sent to your panel, we traverse this list, calling each callback with the appropriate data. This is why your original callback data gets 'blapped', and why you must be careful about using some specific toolbox functions intermingled with the UI Library functions. (it is this interaction that you have noted is not documented as well as it should be, and what we will be working on addressing)
NickB
National Instruments
09-14-2009 11:03 AM
Nick,
Passing "" is originally how I understood your explanation, and also works fine. I got off track there.
Thanks for detail on implementation. I can see how the toolbox has become a bit of a tangle as more functionality is added there. There are several other posts here and workarounds I've used to avoid some of the other pitfalls with the toolbox. I'm not used to making the distinction between it and the UI.
Greg