Проверить интерфейс COM еще жив? - PullRequest
10 голосов
/ 17 августа 2010

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

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

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

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

EDIT:

ИСКЛЮЧЕНИЕ: Исключение первого шанса на 0x7728fbae (kernel32.dll) в Client40.exe: 0x800706BA: сервер RPC недоступен.

Звонок:

    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 ]

6 голосов
/ 20 августа 2010

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

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

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

Однако несколько иная версия этого вопроса отвечает

Был ли еще запущен процесс XXX?

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

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

1 голос
/ 21 августа 2010

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

1 голос
/ 17 августа 2010

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

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

0 голосов
/ 26 августа 2010

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

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

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

0 голосов
/ 20 августа 2010

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

0 голосов
/ 20 августа 2010

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

0 голосов
/ 18 августа 2010

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...