原因
当您启动使用活动模板库 7.0 (ATL) 编写的 Windows NT 服务时, CAtlServiceModule::ServiceMain 函数将设置为 False ,以避免启动服务中最后一个的 COM 对象释放后终止进程的后台线程 m_bDelayShutdown 成员。
定义 _ATL_FREE_THREADED 宏时, 基本的 CAtlServiceModule::PreMessageFilter 函数将服务器的 COM 对象注册 REGCLS_SUSPENDED 标志,但当 m_bDelayShutdown 标志设置为 false 时未调用 CoResumeClassObjects 。
代替方法
要变通解决此问题,重写 CAtlServiceModule::PreMessageLoop 函数。 重写中, 调用该基本 PreMessageLoop 函数,,然后调用 CoResumeClassObjects ,当 m_bDelayShutdown 设置为 false 时。 以下是为属性化和非属性化代码的示例。
非属性化代码
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;
}
};
属性化代码
[ 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;
}
};
更多信息
可以作为独立的 COM 服务器帮助调试时,通过 ATL 启动编写的 Windows NT 服务。 可以为独立的 COM 服务器,或 Windows NT 服务运行 ATL 基于 Windows NT 服务:
- 当您运行 的服务 命令时,应用程序注册到运行 Windows NT 服务。
该服务的生存期被决定按在的系统而不是该服务实现的 COM 对象的生存期。 - 当您运行在 -RegServer 命令应用程序注册到作为独立的 COM 服务器运行。
ATL 服务器等待发布最后一个对象,若要防止不必要的卸载和重新加载服务器的后在后台线程上指定的时间。 这种延迟由该 CAtlExeModuleT::m_bDelayShutdown 成员,并由 CAtlExeModuleT::m_dwTimeOut 成员指定延迟的长度。
时简单 COM 服务器运行服务,m_bDelayShutdown 标志被设置为 true 和 CAtlExeModuleT::PreMessageFilter 调用 CoResumeClassObjects ,这将允许客户端能够成功地创建 COM 对象中。
重现该问题的步骤
<script type="text/javascript"></script>
服务器实现
<script type="text/javascript"></script>
- 打开 Visual Studio.NET 或 Visual Studio 2005。
- 在 文件 菜单上指向 新建 ,然后单击 项目 。
- 项目类型 下, 单击 Visual C++ 项目 ,然后单击模板下的 ATL 项目 。
请注意 在 Visual 的 Studio 2005 中单击 Visual C++ 项目类型 下。 - ATLServiceModule 键入 名称 ,然后单击 确定 。
- 在 ATL 项目向导 中,单击 应用程序设置 。
- 清除 Attributed 复选框。
- 选中 服务 (EXE) 复选框。
- 单击 完成 。
- 在类视图中右键单击 ATLServiceModule ,指向 添加 ,然后单击 添加类 。
- 单击 模板 下的 ATL 简单对象 ,然后单击 打开 。
请注意 在 Visual 的 Studio 2005 中单击 添加 。 - myClass 输入 短的名称 ,然后单击 完成 。
- 在类视图单击以展开 ATLServiceModule 。
- 右键单击 ImyClass ,指向 添加 ,然后单击 添加方法 。
- 输入为 myMethod 在 方法名称 。
- 选择 LONG * 作为 参数键入 ,然后键入作为 参数名称 的 左值 。
- 单击以选中 参数属性 下的 出 复选框。
请注意 在 Visual 的 Studio 2005 中没有执行 step16。 - 单击 添加 ,然后单击 完成 。
- 打开该 MyClass.cpp 文件然后代码并粘贴以下 myMethod 方法中:
// Set the value to 10 *lValue = 10;
- 在解决方案资源管理器右键单击 ATLServiceModule ,然后单击 属性 。
- 单击以展开 C/C++ ,然后单击 命令行 。
- 键入在 附加选项 文本框中的 / D _ATL_FREE_THREADED",,然后单击 确定 。
- 在 生成 菜单上单击 生成解决方案 。
- 打开 Visual Studio.NET 命令提示符,然后再运行作为一个 NT 服务运行 ATLServiceModule 以下命令:
ATLServiceModule.exe 服务
客户端实现
<script type="text/javascript"></script>
- 打开 Visual Studio.NET 或 Visual Studio 2005。
- 在 文件 菜单上指向 新建 ,然后单击 项目 。
- 在 Visual C# 项目 项目类型 下选择 控制台应用程序 模板,然后单击 确定 。
- 在解决方案资源管理器单击以展开项目,右键单击 引用 ,然后单击 添加引用 。
- 单击 浏览 ,然后找到 ATLServiceModule.exe 文件。
- 单击 打开 ,然后单击 确定 。
请注意 在 Visual 的 Studio 2005 中没有单击 打开 。 - 在 Class 1.cs 文件中将以下代码在 Main 中的粘贴函数:
请注意 在 Visual 的 Studio 2005 中默认文件是在 Program.cs 文件。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() );
- 在 生成 菜单上单击 生成解决方案 。
- 在 调试 菜单中上, 单击 没有调试的启动