How to create a STA (Single Threaded apartment) control in VS2010

2.3k Views Asked by At

I have a .NET 4.0 Windows Service that hosts components. Our project lead says that when calling methods on certain components, that performance is slow. He suspects that it may be an STA component that incurs this performance penalty.

To test this theory, I have been asked to create a STA component with one method accepts an integer and returns the integer multiplied by two. This component will be hosted in the service and tests will be run.

Can something like this be created in C# or would it be necessary to create it in C++?

If possible, could you include some code?

EDIT: (code based on Han's suggestion)

using System.Runtime.InteropServices;

namespace STADemo
{
    [ComVisible(true)]
    public class STAClass
    {
        public int Calculate(int value)
        {
            return 2*value;
        }
    }
}
2

There are 2 best solutions below

0
On BEST ANSWER

Windows Service uses MTA threading model. You haven't specified the exact model of the COM components suspected to be causing a slowdown. If they are marked as 'Apartment' or '' (blank) in their ThreadingModel registry entries, that may indeed hurt the performance, because all calls will be marshaled from the Windows Service's current thread to a dedicated thread created by COM to host the components.

If you really need to prove that, you can create an Single-threaded or Apartment-threaded component in C# by providing a custom registration method with [ComRegisterFunction]. Here's an example of using ComRegisterFunction to mark a component as Apartment.

Note, there's still a subtle difference between Single-threaded and Apartment-threaded components in how the class factory object handles threading, as described in this article. Single-threaded components are really rare, your components most likely are Apartment-threaded, but make sure to check their registry keys anyway.

1
On

That's a property of a COM coclass. You can create one by using the [ComVisible] attribute. You register it with Regasm.exe, it will write the ThreadingModel registry key. Which it sets to "Both". You'll have to change it to "Apartment".

This is not a terribly sane way to go about this, you'll merely prove what you already know: marshaling a call from one thread to another is a lot slower than a direct call. Just use the debugger instead. Enable unmanaged debugging and keep an eye on the Debug + Windows + Threads window. If you see another one pop up when you step through the constructor call then you'll have a signal that COM is creating a helper thread to give the COM component a safe home. Pretty likely in a service, it doesn't have STA threads by default unless you create one yourself. Thread.SetApartmentState() call.