3

i am currently developing an windows form application, which communicates with a serial device. The vendor of the device offers a *.dll file including methods for interacting. I added a reference to *.dll file in visual studio.
If i call a function of device library (Get()), i get a response after 2 seconds. To avoid freezing my GUI, i spawn a new thread, which initializes a new instance of the library object and calls the Get()-Method.
However, calling Get() freezes my GUI for exactly 2 seconds. It seems like the object is already initialized in the main thread.
I don't know what i missed in my code. Here comes a snippet of code reproducing my problem:

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MyDevice deviceObj = new MyDevice();
            Thread myThread = new Thread(new ThreadStart(deviceObj.getValues));

            myThread.IsBackground = true;
            myThread.SetApartmentState(ApartmentState.STA);
            myThread.Start();
        }
    }

    class MyDevice
    {
        public void getValues()
        {

            // initialize object of device library
            Tcddka.tcddk tcd = new Tcddka.tcddk();

            // (comPort, identifier, timeout)
            tcd.Init((Int16)(3 - 1), "deviceID", 7000);

            for (int i = 0; i < 10; i++)
            {
                tcd.Get(); // measure new values
                Thread.Sleep(2000);
            }
        }
    }



Thank you in advance for your efforts,
Michael

EDIT: Solution

  1. Implement STAThread, derive your own class of it. Override Initialize() (don't forget to call base.Initialize() and create your COM Object here)
  2. My DLL-Library wasn't registered. Open command line, type in regsvr32 "path to your DLL file"
  3. Open registry, search for your DLL file name, browse to folder InprocServer32 and check if the ThreadingModel is set to Apartment.

Thank you guys !!

Michael
  • 55
  • 6
  • You created the MyDevice object on the wrong thread. The UI thread instead of the worker thread. Calling Application.Run() in an STA thread is required. – Hans Passant Oct 31 '14 at 15:28

2 Answers2

1

I would first check whether the COM component has threading model set in the registry. If the ThreadingModel is not set, the component is created always in the first STA thread. In that case you should contact the component author about this issue. Sure you can set the ThreadingModel to "Apartment" by yourself but I would use it only as temporary fix while waiting the component author to fix the registration.

You must still create the component in another STA thread as Hans Passant suggested.

mgronber
  • 3,399
  • 16
  • 20
  • I checked the registry and the ThreadingModel is not set. I already contacted the author, but have not received a response yet. To fix it, I tried to use this class of [STAThread](https://stackoverflow.com/questions/21680738/how-to-post-messages-to-an-sta-thread-running-a-message-pump?lq=1). I derived my own class and overrided the Initialize function. No success, my Main thread still freezes – Michael Nov 05 '14 at 09:39
  • 1
    You must set the component's ThreadingModel in the registry to Apartment. Otherwise the component will be created in the first STA thread regardless of your actions. With the registry key set, your code should work (presuming you remember to call base.Initialize(...) from the overrided Initialize(...) method). – mgronber Nov 05 '14 at 10:00
0

ApartmentState.STA means:

The Thread will create and enter a single-threaded apartment.

STA have some requirements:

Each single-threaded apartment must have a message loop to handle calls from other processes and apartments within the same process. Single-threaded apartments without objects (client only) also need a message loop to dispatch the broadcast messages that some applications use.

Your main thread and your STA thread are synchronizing with each other via windows messages. If you freeze your STA thread, you may end up freezing your main thread (the main thread is waiting a response from a message sent to STA and the STA does not service it's message loop, thus freezing your GUI). And vice versa. I can't know why is your COM object synchronizing with the main thread, that is something only you can answer.

You should try using an MTA thread, if possible. Not all COM components will work in an MTA.

Remus Rusanu
  • 288,378
  • 40
  • 442
  • 569
  • Using a MTA thread is not working. Do you know how i can add a simple message loop? – Michael Oct 31 '14 at 11:07
  • Having a message loop does not help if you freeze in Sleep (or tcd.Get) w/o servicing the message loop. Try to find why the main thread and the background STA thread need to synchronize. Break in debugger during those two seconds, analyze the stack. – Remus Rusanu Oct 31 '14 at 11:16