Проверьте COM-интерфейс еще живым?

В COM, как проверить, что указатель на COM-объект все еще имеет действительный объект на другом конце?

У меня проблема, когда этот следующий бит кода пытается проверить, остается ли указатель m_pServer, но когда это приложение подвергает этот интерфейс, этот бит кода сбой приложения. Может ли кто-нибудь посоветовать, как проверить указатель перед его использованием?

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

Этот код не работает, если m_pServer больше не находится в памяти.

EDIT:

ИСКЛЮЧЕНИЕ: Исключение с первой вероятностью в 0x7728fbae (kernel32.dll) в Client40.exe: 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 

Ответ 1

То, что вы пытаетесь сделать здесь, просто невозможно. Поскольку m_pServer живет в другом процессе, вы действительно задаете следующий вопрос:

Продолжается ли процесс XXX?

Это просто не ответный вопрос в мире окон (или linux/unix). Вы никогда не сможете надежно ответить на вопрос, потому что, как только на вопрос будет дан ответ, результат может быть недействительным. Процесс может завершаться в любой момент времени, в том числе между вашим проверкой и доступом к COM-объекту.

Однако немного другая версия этого вопроса ответственно

Продолжался ли процесс XXX?

Единственный способ подойти к такой проблеме - выполнить эту операцию и просто ожидать, что она потерпит неудачу. Если это удастся, тогда вы отлично ответили на модифицированную версию вопроса. Если он терпит неудачу, вам нужно интерпретировать отказ, чтобы определить, не завершилась операция или процесс исчез.

Это единственный способ правильно справиться с этой ситуацией.

Ответ 2

Вы можете управлять временем жизни COM-объекта. До тех пор, пока у вас есть живой указатель на интерфейс, вы должны иметь хотя бы один вызов AddRef() на интерфейсе. Окончательный вызов Release() удалит объект, и указатель станет устаревшим. Используя его впоследствии, вы случайно разбиваете свою программу, обычно с помощью AV. Невозможно определить, является ли он устаревшим.

Вы можете установить m_pServer в NULL, когда вы совершаете свой окончательный вызов Release().

Ответ 3

Исключения с первого раза из COM пойманы прокси и сообщаются как коды ошибок. Если вы продолжите исключение из первого шанса, вы должны увидеть прокси-сервер RPC_SERVER_UNAVAILABLE, который вы должны обработать соответствующим образом.

Ответ 4

По сути, вы никогда не проверяете это. Это может дать только бесполезный ответ. Рассмотрим следующий гипотетический пример:

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

Даже если CoCheckAlive вернул true, этот результат не гарантирует, что удаленный сервер останется в живых достаточно долго, чтобы сделать следующий вызов. Вот почему вы просто делаете вызов и обрабатываете случаи отказа (в том числе RPC_E_SERVERDIED).

Ответ 5

Так как это исключение, вы не могли бы просто __try? Вы можете настроить фильтр "Исключения", чтобы просто исключить исключение RPC-сервера. См. http://msdn.microsoft.com/en-us/library/s58ftw19%28VS.80%29.aspx для дальнейшего объяснения того, как это сделать.

Ответ 6

Просто напишите метод-обертку, который проверяет наличие ошибки и ловит это исключение и сообщает об этом как об ошибке.

Ответ 7

1 - Проверьте HRESULT внутри вашего кода, а не только общий FAILED - это даст вам место, из которого вы можете сообщить больше пользователю и или начать альтернативное действие (например, закрыть приложение изящно). Фактический HRESULT может быть или не быть точно RPC_SERVER_UNAVAILABLE - так что назначьте его ti var, чтобы вы могли видеть его в отладчике (и не переходите на исключения с первого раза) - они предназначены для дебютации нижних уровней кода.

2 - Если вы действительно получаете исключение, брошенное в свой код на С++, сначала разместите общий обход вокруг него, а затем посмотрите на него в отладчике. Вероятно, этот случай исходил из умного указателя, пытающегося быть слишком умным: -)

В любом случае оставьте свой код флагом, чтобы узнать, что произошло, и закрыть COM-ссылки изящно - только потому, что сервер умер, не означает, что вам нужно утечка: -)