This documentation is archived and is not being maintained.

ATL Server and COM 

Your ATL Server code usually runs on a thread from the ISAPI extension's thread pool on which COM has been initialized for use in a single-threaded apartment (STA). This initialization occurs in CIsapiExtension::OnThreadAttach. COM is uninitialized in CIsapiExtension::OnThreadTerminate.

If you want to change the way in which COM is initialized, you can override these methods in your ISAPI extension class derived from CIsapiExtension. You do not need to call the base class implementations of these methods; the only thing that they do is initialize and uninitialize COM.

Note that there is some code in your ISAPI extension DLL that does not run on one of the threads from the pool; the code that is executed directly from the CIsapiExtension::GetExtensionVersion, CHttpServer::HttpExtensionProc, and CIsapiExtension::TerminateExtension functions. These functions are executed on threads owned by IIS and call the corresponding methods provided by CIsapiExtension or your derived class. Because you do not own the thread(s) that call these methods, you cannot assume anything about whether or how they have been initialized for COM and you should not try to initialize COM on these threads.

If you need to create an object in your ISAPI extension DLL that requires COM, you have a few choices:

  1. Create the object when the ISAPI extension DLL is initialized. Create your own thread in GetExtensionVersion on which you can initialize COM; however, you need and which calls your ISAPI extension's GetExtensionVersion method. You need to write code so that the IIS thread waits for your thread to finish its task and you'll also need to provide some way to communicate status information back to the IIS thread.

  2. Create the object the first time that it is needed. For example, you could initialize the object the first time a request handler calls QueryService requesting that object. At this point, you know that the code is running on a pool thread that has been COM-initialized in CIsapiExtension::OnThreadAttach or your own override of that method.

    Be careful to synchronize access to your class data members because QueryService can be called simultaneously from multiple threads and make sure that you understand COM's rules for passing interface pointers between threads.

  3. Create the object when the first thread in the pool is initialized. Override CIsapiExtension::OnThreadAttach and execute the initialization code there. The code will have to check whether the object has already been initialized, so that check will run every time a pool thread is created.

  4. Create one object for each thread in the pool when the thread is initialized. You can store interface pointers as data members of your worker thread class derived from CIsapiWorker. Override CIsapiWorker::Initialize, call the base class implementation first to ensure that COM is initialized, and then perform any other initialization that you need to do.

  5. Create multiple objects on demand. For example, create a different object every time a request comes in to QueryService. As before, you know that the code is running on a COM-initialized thread, but this time you do not need to worry about multiple threads accessing the object.

If the resources held by the object are not large, providing one object per thread is a great way of getting scalability without having to write any complicated code if your architecture supports that approach.

You can always create COM objects in your request handlers because this code runs on a thread from the pool on which COM has been initialized. For example, you can create a COM object in a request handler and make it available to other request handlers (or the same request handler on subsequent requests) by passing it to the ISAPI extension so that it can expose it as a dynamic service. For details, see IIsapiExtension::AddService.

See Also