LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

Under NT my CVI program exits when the NT console unlocked

I have a program that runs fine while the console is unlocked. If I try to lock the console and hit ESC or let it lock and log back in the program exits. It doesn't happen with W2000 only on NT. Any ideas? It isn't doing anything at the time but waiting for the user to select which window to display or an external COM connection. This happens whether there is a COM connection or not.
0 Kudos
Message 1 of 10
(4,509 Views)
Hi,

This is an interesting issue. Does this happen with any other CVI programs, or just this particular one? I'm wondering if it registers keystrokes that you use to unlock the console and interprets that as an application close/cancel command of some sort. What happens when you're not locked and you're at that selection screen, but press ESC or a cancel button? Does it perform similarly?

Jeremy L.
National Instruments
Jeremy L.
National Instruments
0 Kudos
Message 2 of 10
(4,509 Views)
It seems to only happen with COM server programs. I've created two of these and it happens to both of them if I start them manually and then connect to them. It happens if I actually lock the console and if I hit escape at the prompt. I am going to try to gut one of them down to the minimum level necessary to recreate this issue. I am working on some time critical stuff now but hopefully I'll be able to do this and forward the project to you by the end of today. I put a break in my exit command and it never executes in this scenario but the app acts as if somebody commanded it to close.
0 Kudos
Message 3 of 10
(4,509 Views)
I'm wondering if locking your system actually forces a disconnection to the COM object you are referencing. If this is the case, then it may make sense that you are erring out of your application and it closes. Without an error handler, the application wouldn't show you a message and you wouldn't know why it closed. I am interested in seeing if you can narrow down the problem and send a sample. It will definitely help us figure out what's going on.

Jeremy L.
National Instruments
Jeremy L.
National Instruments
0 Kudos
Message 4 of 10
(4,509 Views)
This is a possibility but I haven't created any connections to this but the local lock to prevent it from leaving since it was started manually.
I find it weird that this only happens on NT 4.0 machines (all with SP6) and not on any W2000 machines. I should be able to break it down to the simplest possible by the time I leave tonight (I have class for most of the day)

On start up of the COM server I lock it using the code in cbInterface. This is the only code (along with the init code below) that has executed at the time of exit as I haven't launched the client yet.

I deleted the headers and haven't tried this code yet but otherwise this is the code that is running at the time of the problem.

#define MAX_THREADS 30

/// Structure for flagging a section as critical for this process
CRITICAL_SECTION cs;

int exitThreads = 0;
int hThrdPool = 0;
char exitThread = 0;
int hMonSelect = 0;
CAServerObjHandle hGlobeObj = 0;

int __stdcall WinMain (HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
int runServer = 0;
char errBuf [500] = {0};

if (InitCVIRTE (hInstance, 0, 0) == 0)
return -1; // Out of memory

// ActiveX server initialization
if (FAILED (CaSrvrBenchInterfaceInit (
hInstance, lpszCmdLine, &runServer,
errBuf, sizeof(errBuf))))
return -1; // Server initialization error.

if (runServer){
InitializeCriticalSection( &cs );

hFocusSt = LoadPanel (0, "Mirror.uir", PNL_FOC);
hAzElSt = LoadPanel (0, "Mirror.uir", PNL_AZEL);
hSrcSlctSt = LoadPanel (0, "Mirror.uir", PNL_SRC);
hTargetWhl = LoadPanel (0, "TgtFltr.uir", PNL_TGT);
hIRSrc = LoadPanel (0, "IRVisSrc.uir", PNL_IR);
hVisSrc = LoadPanel (0, "IRVisSrc.uir", PNL_VIS);
hChopper = LoadPanel (0, "ChopperGUI.uir", PNL_CHP);
hAzElDraw = LoadPanel (0, "MirrorMtn.uir", PNL_AEDRAW);
hAzElMtn = LoadPanel (0, "MirrorMtn.uir", PNL_AEMTN);
hMonSelect = LoadPanel (0, "CtlSelect.uir", PNL_MON);
hVac = LoadPanel (0, "Vac.uir", PNL_VAC);

CmtNewThreadPool (MAX_THREADS, &hThrdPool);
DisplayPanel(hMonSelect);

RunUserInterface (); // Process messages

// Flag the threads to exit and let them do it
exitThreads = 1;
ProcessSystemEvents ();
ProcessSystemEvents ();

// We need to monitor this and check how long it is taking
CmtGetThreadPoolAttribute (hThrdPool, ATTR_TP_NUM_ACTIVE_THREADS, &qtyRunning);
CmtDiscardThreadPool (hThrdPool);

DiscardPanel (hVac);
DiscardPanel (hAzElMtn);
DiscardPanel (hAzElDraw);
DiscardPanel (hChopper);
DiscardPanel (hVisSrc);
DiscardPanel (hIRSrc);
DiscardPanel (hTargetWhl);
DiscardPanel (hSrcSlctSt);
DiscardPanel (hAzElSt);
DiscardPanel (hFocusSt);
}

// ActiveX server cleanup
CaSrvrBenchInterfaceUninit (hInstance);

return 0;
}

/******************************************************************************/
/* ActiveX Server Callback Function */
/* */
/* Events: */
/* 1) CA_SERVER_EVENT_MODULE_EXIT */
/* */
/******************************************************************************/

int CVIFUNC cbServer (int event)
{
HRESULT retVal = S_OK;

return retVal;
}


/******************************************************************************/
/* ActiveX Object Callback Function(s) */
/* */
/* Events: */
/* 1) CA_SERVER_EVENT_OBJECT_CREATE */
/* 2) CA_SERVER_EVENT_OBJECT_DESTROY */
/* */
/******************************************************************************/

HRESULT CVIFUNC cbInterface (
CAServerObjHandle objHandle, const CLSID *pClsid,
int event, void *callbackData)
{
HRESULT retVal = S_OK;

if(event == CA_SERVER_EVENT_OBJECT_CREATE){
hGlobeObj = objHandle;
CA_ServerLockActiveObject (hGlobeObj);
ProcessSystemEvents ();
}

return retVal;
}
0 Kudos
Message 5 of 10
(4,509 Views)
I was able to create a project that acts the same way as my applications, I don't think I can get it much smaller.

Any help, comments, pointers will be greatly appreciated as this problem is a major stumbling block.
0 Kudos
Message 6 of 10
(4,509 Views)
I was able to reproduce the issue here on a NT machine with SP6. I'm wondering if this is an issue with the way NT handles locking the workstation and returning. I tried doing a little bit of debugging and saw that every time I ran it, I went through RunInterface fine, and the application just sat and waited. Then, I would lock the workstation and return. Immediately following that, I catch a breakpoint in the server callback, which runs and then returns to the main function where i am now passed runuserinterface. I'm wondering if an event is being passed to quit the user interface. I have to do a little more testing and hopefully I can find some message that's being passed to the application to make it quit.

Jerem
y L.
National Instruments
Jeremy L.
National Instruments
0 Kudos
Message 7 of 10
(4,509 Views)
Have you been able to find out how to get around this?
0 Kudos
Message 8 of 10
(4,509 Views)
Hi,

I haven't found anything yet to elegantly get around it. Although, this is definitely an issue with just NT 4.0. I haven't been able to capture any messages that cause the close, either. The only suggestion I have at this point would be to handle the close in the program. The way to do this would be to have your RunUserInterface() in a while loop that's controlled by some global flag. The only way this flag can be set is through explicitly pressing the Quit button, which in the callback you set the flag. So essentially, you will always be in the loop of RunUserInterface() (which itself is continuously running while loop) until you set this flag by pressing the Quit button. The reason I think
this would work is because I was able to set breakpoints after RunUserInterface in the code, and every time I came back from locking the workstation, I would catch that breakpoint. So, I believe the code is running to clean up and close out when you return. I would try this and see if it makes a difference!

Jeremy L.
National Instruments
Jeremy L.
National Instruments
0 Kudos
Message 9 of 10
(4,509 Views)
I added a COM class callback to each COM class and did the check on the global there, returning false if the user hadn't actually requested to exit when the server is checking if it can exit. If the check is done at the outer level the COM server has actually quit by then and another instance will be started to be the COM server.

HRESULT CVIFUNC cbApp (CAServerObjHandle objHandle, const CLSID *pClsid, int event, void *callbackData)
{
HRESULT retVal = S_OK;

if(event == CA_SERVER_EVENT_OBJECT_CREATE){
if(startFlag > 0){
if(!hLocal){
CA_ServerLockActiveObject (objHandle);
hLocal = objHandle;
}
}els
e{
startFlag = -1;
}
}

if(event == CA_SERVER_EVENT_OBJECT_DESTROY){
if((startFlag < 0) && (exitCOMServer)){
if(hLocal) {
CA_ServerUnlockActiveObject (hLocal);
hLocal = 0;
}
}else{
retVal = S_FALSE;
}
}

return retVal;
}

My "fix" causes "improper" COM behavior by making either an interactive user or the COM client to specifically tell my server to exit. This isn't causing a problem in my situation as this is the behavior we wanted but there are many situations where this can be a problem.

Thanks,
Lloyd
0 Kudos
Message 10 of 10
(4,508 Views)