LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

RunUserInterface a non blocking function?

Hi,
 
I was told that if I call RunUserInterface from my application it will block the user interface so I will need to close the panel to proceed with other tasks. What happens in my application is that I call it and I still have access to UI that called it. Meaning I can close it without closing my panel. In this case the callback function is not called ( this is where QuitUserInterface is called ) and it hangs. I hope I am clearly explaining this.
I tried explicitly calling QuitUserInterface when my dll unloads but that throws GPF, not sure if the panel is created in a different thread. I also tried intercepting other events but it did not help (EVENT_DISCARD).
Any ideas on what else I could try?
Thanks
J.
0 Kudos
Message 1 of 11
(5,910 Views)

Hi Cimteker,

I'm still a little confused as to what behavior you are seeing. The
RunUserInterface function is responsible for running the UI and pumping messages (i.e. issuing events to callback functions).  It doesn't return until you call the QuitUserInterface function.  Now you mentioned a different thread but didn't clarify what was running on that thread. There are things to consider when using multiple threads with regards to RunUserInterface and QuitUserInterface. For example, it is not a recommended practice to call QuitUserInterface and RunUserInterface in different threads. The best approach when dealing with UIs and multithreading is to always process messages for the current window in the same thread that created the window.

However, you could use the
PostDeferredCall function which schedules CVI to call a specific function at the next occurrence of GetUserEvent, RunUserInterface, or ProcessSystemEvents,By default, PostDeferredCall posts the call to the main thread which called RunUserInterface. To schedule CVI to call a function in a thread other than the main thread, use PostDeferredCallToThread. The function that is posted to the main thread would then call QuitUserInterface .  Refer to the The LabWindows/CVI Function QuitUserInterface() Isn't Working KnowledgeBase for information. This may or may not be applicable to your scenario as I'm not fully clear on your problem.

Are you spawning off multiple threads?
Do you have multiple panels?

There is a variety of threading topics in the Library Reference >> User Interface Library >>> Multithreading category in the NI LabWindows/CVI. The topic Event Processing and Multithreading states that in general, CVI invokes UI callbacks in the same thread in which you create the panel or menu bar to which the callback event applies. This applies to all controls on panel with a few exceptions that are listed in the help.

I assume you are using
LoadLibrary and FreeLibrary for your DLL?
At what point in your code are you unloading the DLL (i.e. after
RunUserInterface returns, before QuitUserInterface, etc)

Take a look at those topics in the help as they are really good.

Hope this helps!

Best Regards,

Jonathan N.
National Instruments
0 Kudos
Message 2 of 11
(5,908 Views)

Hi  Jonathan,

Thanks for your reply. I knew it would be difficult to explain. I'll take another stab at it.

I have a test executive that loads my dll. My dll contains test functions and a debugger. I ask the test executive to load my debugger. This is where RunUserInterface gets called, it's a callback to my dll by the test executive. Now the debugger is running. Everything is fine. I can close the debugger and the panel's callback  function is called where it calls QuitUserInterface, all's well.

But my test executive's interface (GUI) is active, meaning I can press the X button and unload my dll. This is when the trouble starts. The panel's callback function is never called, I mean maybe it is but not with EVENT_CLOSE, and this is the event that I am handling.

Here's my callback function:

int CVICALLBACK Debugger_plCallback(int panelHandle, int event, void *callbackData, int eventData1, int eventData2)
{
 switch (event)
 {
  case EVENT_CLOSE:
   Dbg_Close();
   QuitUserInterface(idDebugPanel);
   break;
 }
 return 0;
}

The final result is that the dll does not get unloaded as I have some timers that are still ticking and they are not deactivated (normally Dbg_Close shuts them down). A person here that has more exeperience told me that it used to be different. When you called the debugger, it would not allow you to access the X to unload the dll, it would block the UI for the process that called it, that's why I it called it blocking. Is it possible that it works differently under CVI 8.5 that I am currently using?

I do not have any threads and I don't think I need them. Whatever I need the system to do can be achived with just one thread. I was thinking that a panel should behave like a modal dialog under Windows (it requires the user to interact with it before they can return to operating the parent application) . Can it be something wrong with the way I am calling it? Here's what the code looks like:

 hDebugPanel = LoadPanelEx(0, "DebugPanel.uir", plDebugger, __CVIUserHInst);
 Dbg_Init();
 idDebugPanel = RunUserInterface();
 DiscardPanel (hDebugPanel);
 hDebugPanel = 0;  

Thanks a bunch for your help again

J.

 

 

0 Kudos
Message 3 of 11
(5,905 Views)
Hi Cimteker,

Okay, so let me repeat what I see as your scenario.  So if I understand correctly, your test executive is some CVI executable with a UI that loads a DLL which also contains a UI (i.e. the debugger).  So in this case, it seems like you have two panels loaded and viewable (i.e. the debugger panel is in front of the test executive panel). Are those correct statements?

You say that "I can close the debugger and the panel's callback function is called where it calls QuitUserInterface, all's well." So are you saying that when you close the debugger panel window, and then click the X on the test executive panel window, the EVENT_CLOSE event is fired and everything works?  But the scenario that doesn't work is when you still have the debugger panel up and you click on the test executive's X to close the window? In that case, you are seeing the EVENT_CLOSE not fire?

Now from your posted code snippet of LoadPanelEx, this shows that you have a top-level window. I can tell that because you are passing 0 in for the parentPanelHandle parameter of LoadPanelEx. When you pass 0, the panel is loaded as a top-level panel? Are both the test-executive and debugger panels top-level windows?

Before I make any more assumptions (which could be wrong), I'll let you respond and correct any statements I had.

Also, is it possible to provide a very basic watered-down version of something I could run and test?

As far as the threads go, I was just trying to clarify what you had in your program and not suggesting you need to use them. Just trying to grasp your situation.

Best Regards,
Jonathan N.
National Instruments
0 Kudos
Message 4 of 11
(5,901 Views)

No, my test executive is not CVI based, it is Borland C++ based, so I do not have 2 panels loaded.

When I close the debugger panel EVENT_CLOSE event is being fired, as I call QuitUserInterface(0) inside EVENT_CLOSE handler EVENT_DISCARD event is fired. At least that's what I think the sequence of operation is. When I unload the dll, EVENT_CLOSE event is NOT fired, just EVENT_DISCARD. I tried putting my code in EVENT_DISCARD event handler but it crashes. I am thinking because it is too late, the interface is already distroyed, so my call to QuitUserInterface(0) crashes.

Yes, I am passing 0 to my LoadPanelEx call as I do not have a panel handle for my test executive, it is not CVI based.

Thanks for you help.

J.

0 Kudos
Message 5 of 11
(5,861 Views)
Hi Cimteker,

So if I understand correctly, your test executive calls a CVI built DLL which loads up a panel. You then see problems when you unload the DLL first and then try and close the panel. Is that correct?

If that's the case, you should never be following those steps.  You should always close the panel first before unloading your DLL.  At this point, I'm honestly not sure what would happen with regards to the CVI RT and the panel.  This is something I need to investigate to see what actually happens since those steps put CVI into a bad state. Thus, GPF's might occur which is what you are seeing.

The recommended approach to unload the DLL after your UI is unloaded from memory and completly gone.  From what I can tell, this works for you as it should work and is the recommended practice.

I'll let you know what I find with regards to what happens when you unload a DLL from memory before closing the panel.

Best Regards,
Jonathan N.
National Instruments
0 Kudos
Message 6 of 11
(5,848 Views)
Hi Cimteker,

How are you determining that an EVENT_DISCARD is being fired during the unload DLL case? In my test, I unloaded a DLL before closing the panel and then the panel didn't receive any UI events at all. This would make sense since there's no callback in memory for it to jump to. 

My example was very basic with a C++ application dynamically loading a CVI DLL with a GUI. I then had a function that unloaded the DLL from memory. At that point, the UI was still visible but it wasn't accepting any events. 

Is there something I'm missing?

Best Regards,
Jonathan N.
National Instruments
0 Kudos
Message 7 of 11
(5,827 Views)

I had a message box pop up in my handler:

 switch (event)
 {
  case EVENT_DISCARD: 
   MessageBox(NULL,"EVENT_DISCARD","EVENT_DISCARD FIRED",MB_OK);
    Dbg_Close();
    QuitUserInterface(0);//The value passed to QuitUserInterface becomes the value returned by RunUserInterface
   break;
  case EVENT_CLOSE:
   MessageBox(NULL,"EVENT_CLOSE","EVENT_CLOSE FIRED",MB_OK);
   Dbg_Close();
   QuitUserInterface(0);
   break;
...

When I was closing my debugger I had EVENT_CLOSE first and then EVENT_DISCARD. When I was unloading it was just EVENT_DISCARD.

This may have something to do with how a particular application unloads a dll.

Thank you

J.

 

0 Kudos
Message 8 of 11
(5,825 Views)
Hi Cimteker,

Yeah, that's what I had in my panel callback function. I assume that code is inside your panel callback event handler? Now, I was using the native MessagePopup function to display a message but it seems that you have some "user-implemented" message box. Not sure if that matters, but just saw that. 

Are you doing anything unique in DLL_PROCESS_ATTACH for your DLLMain? 

You shouldn't be receiving messages on your UI after the DLL has been unloaded. 

Is it possible that you can give me some small code that I can run? The behavior you are seeing just isn't adding up. 

When you say unload your DLL, are you simpy calling FreeLibrary? Or are you doing that plus some other stuff?

Best Regards,

Jonathan N.
National Instruments
0 Kudos
Message 9 of 11
(5,819 Views)

Hi Johnathan,

I think I have a native WIN32 message popup, I do not rememeber implementing anything custom. 

As far as DLL_PROCESS_ATTACH for my DLLMain I cannot answer this question. Like I said it is an off-the-shelf test executive that we're using here, I do not have a source code and do not know how it handles dll load/unload.

I have a callback from my test executive on DLLUnload. Is there anything I can put there that could gracefully close the debugger (panel). If I can close it by pressing X in the right top corner I should also be able to close it programatically be calling a function.

Thanks for your help,

Jerry.

0 Kudos
Message 10 of 11
(5,792 Views)