NI TestStand

cancel
Showing results for 
Search instead for 
Did you mean: 

Running TestStand Engine in a Windows Service

Greetings!

 

I have a weird and particular problem that I hope you can help me with.

 

I am trying to build a web-based application that uses a 3rd party test database that is only accessible using TestStand.  As a result, I need to run the TS Engine on a server. 

 

I built the application and it runs fine in the Visual Studio web server, but it didn't work in IIS -- it seemed that the threads I launched to process the engine events would die after a short while.  I rewrote the application to put the TS Engine into a Windows Service.  This works fine in WinXP (32-bit).  The service works in Visual Studio's WfcSvcHost (a test client) on Windows 2K3 (64-bit), but doesn't work when installed as a Windows Service in 2K3 (64-bit).  The TestStand engine code just hangs at the constructor for the TS Engine ... it doesn't crash, no exceptions are thrown, and if I stop it with the debugger, the thread is in the constructor.

 

Any thoughts on what is going on?

 

(Yes, I know TS is not supported on Win 2K3 64-bit ... but I must use it as all my servers run that.)

 

Thanks,

Tom M.

Message 1 of 8
(5,043 Views)

I'm not sure about the service problem, but if it's possible to create your own threads in IIS you might be able to workaround the problem you were seeing there by creating your own thread that then creates the teststand engine, that way you can control the lifetime of the thread.

 

Also, the TestStand engine expects the thread that creates it to be the one that will process window messages for dispatching UIMessages, so for things to work correctly you will need a message loop running in that thread at some point after creating the engine.

 

Hope this helps,

-Doug

0 Kudos
Message 2 of 8
(5,021 Views)

Hi Doug,

How does one control the lifetime of threads in IIS?  When I tried in IIS my threads were dying unpredictably and I decided that maybe this was a normal behaviour for a web server .. who would normally want processes to outlive the duration of a request? (I say ironically, because I do!)

 

With regards to your second comment, I discovered this also.  Though what I find weird is that the engine only seems to run during my calls to execution.WaitForEnd(...)  ... I couldn't find any other method that tells the engine to do work.  So I wind up calling WaitForEnd(....) on executions I know to be already complete (when I have no active executions) in order to "run" the engine.  Is there so other method I'm missing?

 

Regards and Thanks,

Tom M.

0 Kudos
Message 3 of 8
(5,016 Views)

I don't really know anything about IIS so I'm not really sure what is best, but if you keep running code in a IIS thread and never return from it until your application is done then the thread will likely be around at least as long as your code is running. The code you should be running is likely a message loop, which is related to the other issue you are asking about, about the engine running.

 

The other issue you are asking about, about the engine running, is that you need to have a message loop in your main thread (the one that creates the engine) in order for the UIMessages to be processed (i.e. for the engine to run). Typically, programs which display windows have code which does this for you whenever your application is idle. If your program does not really have a UI, then you might need to implement the message loop yourself. In C a Windows message loop looks something like the following:

 

Here's a message loop which uses GetMessage() (which blocks until a message is available):

 

MSG msg;
while (GetMessage(&msg, NULL, 0, 0))

{
     TranslateMessage(&msg);

     DispatchMessage(&msg);
}
 

 

If you want to be able to do other things while processing messages you can use the non-blocking PeekMessage() function instead:

 

#define MAX_NUM_MSGS_TO_PROCESS_AT_A_TIME 100

MSG msg;
int numMsgsProcessed = 0;
while (numMsgsProcessed < MAX_NUM_MSGS_TO_PROCESS_AT_A_TIME && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
     TranslateMessage(&msg);
     DispatchMessage(&msg);

     numMsgsProcessed++;

}

 

See Microsoft's documentation for these functions on http://msdn.microsoft.com for more information.

 

Ideally, the thread that creates the engine should be doing Window message processing whenever it is idle until the application exits (Typically until a WM_QUIT message is sent at which point GetMessage will return FALSE thus exiting the loop, or you can create your own mechanism for telling the main thread when to exit the loop).

 

Hope this helps,

-Doug

0 Kudos
Message 4 of 8
(4,978 Views)

Hi Doug,

 

Thanks.  Though of course this doesn't solve my win2k3x64 problem, it does make my message pumping much cleaner.  I used your advice to generate the code below.  It isn't a loop itself, but I already had a loop -- just no mechanism to pump windows messages.  Now I do! (Thanks again!)

 

Regards,

Tom M.

 

    class MessagePump
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct NativeMessage
        {
            public IntPtr handle;
            public uint msg;
            public IntPtr wParam;
            public IntPtr lParam;
            public uint time;
            public System.Drawing.Point p;
        }

        const uint PM_NOREMOVE = 0x0000;
        const uint PM_REMOVE = 0x0001;

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool PeekMessage(out NativeMessage lpMsg, IntPtr hWnd, uint wMsgFilterMin,
           uint wMsgFilterMax, uint wRemoveMsg);

        [DllImport("user32.dll")]
        static extern bool TranslateMessage(ref NativeMessage lpMsg);

        [DllImport("user32.dll")]
        static extern IntPtr DispatchMessage(ref NativeMessage lpmsg);

        /// <summary>
        /// Processes Windows Messages for the current thread.
        /// </summary>
        /// <param name="max_messages"></param>
        /// <returns>Number of messages were processed, if any.</returns>
        public static int ProcessWindowsMessages(int max_messages)
        {
            NativeMessage msg = new NativeMessage();
            int numMsgsProcessed = 0;
            while (numMsgsProcessed < max_messages && PeekMessage( out msg, IntPtr.Zero, 0, 0, PM_REMOVE))
            {
                TranslateMessage(ref msg);
                DispatchMessage(ref msg);

                numMsgsProcessed++;

            }

            return numMsgsProcessed;
        }

    }

 

 

0 Kudos
Message 5 of 8
(4,963 Views)

Glad the message processing information was useful. I think to fix the issues you have with doing things from a server you need to create and own the thread that you create the teststand engine in and have a message processing loop in that thread (it will also be the thread than the UIMessage event callback is called in). That thread should just never return until you are done with the teststand engine (you can use some sort of inter-thread communication to tell it when to exit). I'm really not sure what you are currently doing though. Perhaps if you explain it in more detail, like what threads exist, how your code is being run, how the engine is being shared between threads, etc. I might be able to suggest a better solution.

 

Hope this helps,

-Doug

0 Kudos
Message 6 of 8
(4,949 Views)

Hi Doug,

 

Actually, what you describe is pretty much what I am doing.  And it works in several types of applications:

 

-console (on WinXP-32, Win 2K3-64)

-in the ASP.NET development server (on WinXP-32, Win 2K3-64)

-WCF service hosted in WcfSvcHost (a test host for WCF) (on WinXP-32, Win 2K3-64)

-WCF service installed as a Windows Service (on WinXP-32)

 

My problem is WCF in Windows Service on Win 2K3-64...  my thread just disappears into the constructor for the Engine ... never comes back.  If I hadn't seen so many cases where it does work (on 2K3-64) I'd just let it go.

 

Thanks,

Tom M.

0 Kudos
Message 7 of 8
(4,946 Views)

One thing that might be a factor is that on newer versions of Windows (at least on Vista so maybe they also do this on Windows server) it is no longer possible to run a service as interactive (i.e. an interactive service is one that displays windows). I think they do this for security reasons. Perhaps a messagebox is being displayed, but can't be shown because it is in the process of the service?

 

Hope this helps,

-Doug

0 Kudos
Message 8 of 8
(4,920 Views)