ATL 7.0 free-threaded Windows NT service does not create COM objects (320116)



The information in this article applies to:

  • Microsoft Visual C++ 2005 Express Edition
  • Microsoft Visual C++ .NET (2002)

This article was previously published under Q320116

SYMPTOMS

When client applications try to create an instance of a Component Object Model (COM) object in a free-threaded Windows NT service, the applications time out, and you receive the following error message:

(0x80080005): Server Execution Failed

You can create instances of the COM objects as expected, when the server is configured to run as a simple COM server.

CAUSE

When you start a Windows NT service that was written by using Active Template Library 7.0 (ATL), the CAtlServiceModule::ServiceMain function sets the m_bDelayShutdown member to false to avoid starting a background thread that ends the process when the last COM object in the service is released.

When the _ATL_FREE_THREADED macro is defined, the base CAtlServiceModule::PreMessageFilter function registers the server's COM objects with the REGCLS_SUSPENDED flag, but does not call CoResumeClassObjects when the m_bDelayShutdown flag is set to false.

WORKAROUND

To work around this problem, override the CAtlServiceModule::PreMessageLoop function. In the override, call the base PreMessageLoop function, and then call CoResumeClassObjects when m_bDelayShutdown is set to false. The following are examples for attributed and non-attributed code.

Non-attributed Code

class CAtlServiceModule : public CAtlServiceModuleT<CAtlServiceModule, IDS_SERVICENAME>
{
public :
   DECLARE_LIBID(LIBID_AtlServiceLib)
   DECLARE_REGISTRY_APPID_RESOURCEID(IDR_ATLSERVICE, "{40264CD5-A316-4ED6-A2D1-2BA3D3210BCE}")

   HRESULT PreMessageLoop(int nShowCmd)
   {
      HRESULT hr;
      hr = CAtlServiceModuleT<CAtlServiceModule,IDS_SERVICENAME>::PreMessageLoop(nShowCmd);


      // workaround
      if (hr==S_OK && !m_bDelayShutdown)
         hr = CoResumeClassObjects();

      return hr;
   }
};

Attributed Code

[ module(SERVICE, uuid = "{82B6FF93-10CB-4A0B-88F4-A41D17ADC84B}", 
   name = "AtrService", 
   helpstring = "AtrService 1.0 Type Library", 
   resource_name="IDS_SERVICENAME") ]
class CServiceModule
{
public:
   HRESULT PreMessageLoop(int nShowCmd)
   {
      HRESULT hr;
      hr = CAtlServiceModuleT<CServiceModule,IDS_SERVICENAME>::PreMessageLoop(nShowCmd);

      // workaround
      if (hr==S_OK && !m_bDelayShutdown)
         hr = CoResumeClassObjects();

      return hr;
   }
};

STATUS

Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article.

MORE INFORMATION

You can start Windows NT services that were written with ATL as stand-alone COM servers to help while debugging. You can run an ATL-based Windows NT service as either a stand-alone COM server, or as a Windows NT service:
  • When you run the -Service command, the application is registered to run as a Windows NT service.

    The lifetime of the service is dictated by the system, and not by the lifetime of the COM objects that the service implements.
  • When you run the -RegServer command, the application is registered to run as a stand-alone COM server.

    ATL servers wait for a specified time on a background thread, after the last object is released, to prevent unnecessary unloading and reloading of the server. This delay is controlled by the CAtlExeModuleT::m_bDelayShutdown member, and the length of the delay is specified by the CAtlExeModuleT::m_dwTimeOut member.
When you run the service as a simple COM server, the m_bDelayShutdown flag is set to true and CAtlExeModuleT::PreMessageFilter calls CoResumeClassObjects, which permits clients to create the COM objects successfully.

Steps to Reproduce the Behavior

Server Implementation

  1. Open Visual Studio .NET or Visual Studio 2005.
  2. On the File menu, point to New, and then click Project.
  3. Under Project Types, click Visual C++ Projects, and then click ATL Project under template.

    Note In Visual Studio 2005, click Visual C++ under Project Types.
  4. Type ATLServiceModule as the Name, and then click OK.
  5. In the ATL Project Wizard, click Application Settings.
  6. Clear the Attributed check box.
  7. Select the Service (EXE) check box.
  8. Click Finish.
  9. In the Class view, right-click ATLServiceModule, point to Add and then click Add Class.
  10. Click ATL Simple Object under Templates, and then click Open.

    Note In Visual Studio 2005, click Add.
  11. Enter myClass as the Short Name, and then click Finish.
  12. In Class view, click to expand ATLServiceModule.
  13. Right-click ImyClass, point to Add, and then click Add Method.
  14. Enter myMethod as the Method Name.
  15. Select LONG* as the Parameter type, and then type lValue as the Parameter name.
  16. Click to select the out check box under Parameter attributes.

    Note In Visual Studio 2005, you do not have to do step16.
  17. Click Add, and then click Finish.
  18. Open the MyClass.cpp file, and then paste the following code in the myMethod method:

    // Set the value to 10
    *lValue = 10;

  19. In Solution Explorer, right-click ATLServiceModule, and then click Properties.
  20. Click to expand C/C++, and then click Command Line.
  21. Type /D "_ATL_FREE_THREADED" in the Additional Options text box, and then click OK.
  22. On the Build menu, click Build Solution.
  23. Open the Visual Studio .NET command prompt, and then run the following command to run ATLServiceModule as an NT Service:

    ATLServiceModule.exe -service

Client Implementation

  1. Open Visual Studio .NET or Visual Studio 2005.
  2. On the File menu, point to New, and then click Project.
  3. Under the Visual C# Projects Project Types, select the Console Application template, and then click OK.
  4. In Solution Explorer, click to expand the project , right-click References, and then click Add Reference.
  5. Click Browse, and then locate the ATLServiceModule.exe file.
  6. Click Open, and then click OK.

    Note In Visual Studio 2005, you do not have to click Open.
  7. In the Class1.cs file, paste the following code in the main function:

    Note In Visual Studio 2005, the default file is the Program.cs file.

    int myIntValue = 0;
    
    // Create the instance of the COM object.
    ATLServiceModuleLib.myClass myObject = new ATLServiceModuleLib.myClass();
    
    // Make the method call. 
    myObject.myMethod( out myIntValue );
    
    // Print the return value on the console.
    Console.WriteLine( "The value returned by the COM method is : " +myIntValue.ToString() );

  8. On the Build menu, click Build Solution.
  9. On the Debug menu, click Start Without Debugging.

    You receive the error message that is mentioned in the "Symptoms" section of this article.

REFERENCES

For additional information about the CoRegisterClassObject function and the CoResumeClassObjects function, visit the following MSDN Web sites:

Modification Type:MajorLast Reviewed:12/30/2005
Keywords:kbConsole kberrmsg kbATLServer kbbug kbpending kbService KB320116 kbAudDeveloper kbAudITPRO