检查COM接口是否还活着?

时间:2010-08-17 08:10:01

标签: c++ com

在COM中如何验证指向COM对象的指针在另一端是否仍然具有有效对象?

我遇到一个问题,即下面的代码尝试检查m_pServer指针是否仍处于活动状态,但是当该应用程序暴露该接口时,这段代码会使应用程序崩溃。有人可以建议如何在使用之前检查指针吗?

if (FAILED(m_pServer->StillAlive())) { // do something }

如果m_pServer不再在内存中,则此代码将失败。

编辑:

EXCEPTION: Client40.exe中0x7728fbae(kernel32.dll)的第一次机会异常:0x800706BA:RPC服务器不可用。

CALL STACK:

    kernel32.dll!RaiseException()  + 0x58   
    rpcrt4.dll!RpcRaiseException()  + 0x3e  
    rpcrt4.dll!NdrProxyErrorHandler()  + 0x28   
    rpcrt4.dll!NdrProxySendReceive()  + 0xa4    
    rpcrt4.dll!NdrProxySendReceive()  + 0x119   
    rpcrt4.dll!NdrComplexArrayMarshall()  + 0x26d   
--> Client40.exe!SlaveDriver::run()  Line 97 + 0x14 C++  //Runs while loop, to handle requests
    Client40.exe!DThread::tfunc(void * thisptr=0x0047e694)  Line 56 + 0xd   C++
    Client40.exe!_threadstartex(void * ptd=0x01b20e00)  Line 241 + 0xd  C
    kernel32.dll!BaseThreadInitThunk()  + 0x12  
    ntdll.dll!RtlInitializeExceptionChain()  + 0x63 
    ntdll.dll!RtlInitializeExceptionChain()  + 0x36 

7 个答案:

答案 0 :(得分:6)

你在这里想做的事情根本不可能。因为m_pServer生活在另一个过程中,所以你真的会问下面的问题

  

流程XXX是否仍在运行?

这在Windows(或linux / unix)世界中根本不是一个可回答的问题。您永远无法可靠地回答问题,因为在问题得到解答的那一刻,它的结果可能会失效。进程可以在任何时间点终止,包括在您的检查和COM对象的访问之间。

然而,这个问题略有不同的版本是可以回答的

  

Process XXX仍在运行吗?

解决这样的问题的唯一方法是执行有问题的操作,并且只是期望它失败。如果它成功那么好你已经回答了问题的修改版本。如果失败则需要解释失败以确定操作是否失败或过程是否消失。

这是正确处理这种情况的唯一方法。

答案 1 :(得分:1)

由您来管理COM对象的生命周期。只要你有一个指向接口的实时指针,你就在接口上至少有一个AddRef()调用。最终的Release()调用将删除对象,指针变为陈旧。之后使用它会使程序随机崩溃,通常使用AV。没有办法检测它是否陈旧。

您可以在进行最终的Release()调用时将m_pServer设置为NULL。

答案 2 :(得分:1)

来自COM的第一次机会异常被代理捕获并报告为错误代码。如果您继续通过第一次机会异常,您应该看到代理返回RPC_SERVER_UNAVAILABLE,您应该根据需要处理它。

答案 3 :(得分:0)

从根本上说,你永远不会检查这个。它只能给出一个无用的答案。考虑以下假设的例子:

if (CoCheckAlive(ptr)) {
  ptr->Foo();
}

即使CoCheckAlive返回true,该结果也不能保证远程服务器能保持足够长的时间来进行下一次呼叫。这就是为什么你只是进行调用,然后处理失败的情况(包括RPC_E_SERVERDIED)。

答案 4 :(得分:0)

因为它是一个例外,你不能只是__try吗?您可以设置一个Exception过滤器来捕获RPC-Server不可用的异常。有关如何执行此操作的详细说明,请参阅http://msdn.microsoft.com/en-us/library/s58ftw19%28VS.80%29.aspx

答案 5 :(得分:0)

只需编写一个包装器方法来检查失败并捕获异常并将其报告为失败。

答案 6 :(得分:0)

1 - 检查代码中的HRESULT - 不仅仅是一般的FAILED - 它将为您提供向用户报告更多内容的地方,或者启动替代操作(例如优雅地关闭应用程序)。实际的HRESULT可能是也可能不是RPC_SERVER_UNAVAILABLE - 所以firt为它分配一个var,这样你就可以在调试器中看到它(并且不会在第一次机会异常时跳转 - 它们用于重新编译较低层的代码)。

2 - 如果你实际上在你的C ++代码中抛出了异常,那么首先对它进行一般性捕获,然后在调试器中查看它。这种情况可能来自于那种试图过于聪明的智能指针: - )

在任何情况下,请将代码留下标志以了解发生的情况并优雅地关闭COM引用 - 仅仅因为服务器已经死亡并不意味着您必须泄漏: - )