2013-05-03 3 views
0

Я поддерживаю приложение, которое использует значки оверлеев Windows Explorer. Иногда некоторые операции требуют, чтобы я принудительно обновлял представление исследователей для определенной папки. Я так используя следующую функцию, которая использует COM:Почему этот COM-код протекает?

void RefreshExplorerView(CString strPath) 
{ 
    CComPtr<IShellWindows> pShellWindows; 

    CoInitialize(NULL); 

    if(SUCCEEDED(pShellWindows.CoCreateInstance(CLSID_ShellWindows))) 
    { 
     IDispatch* pFolder=NULL; 
     VARIANT variant; 
     V_VT(&variant) = VT_I4; 

     for(V_I4(&variant) = 0; pShellWindows->Item(variant, &pFolder) == S_OK; V_I4(&variant)++) 
     { 
      CComPtr<IWebBrowserApp> pWebBrowserApp; 
      if(SUCCEEDED(pFolder->QueryInterface(IID_PPV_ARGS(&pWebBrowserApp)))) 
      { 
       BSTR LocationURL = NULL; 
       pWebBrowserApp->get_LocationURL(&LocationURL); 

       if(LocationURL != NULL && strPath.CompareNoCase(LocationURL) == 0) 
       { 
        CComPtr<IServiceProvider> pServiceProvider; 
        if(SUCCEEDED(pWebBrowserApp->QueryInterface(IID_PPV_ARGS(&pServiceProvider)))) 
        { 
         CComPtr<IShellBrowser> pShellBrowser; 
         if(SUCCEEDED(pServiceProvider->QueryInterface(IID_PPV_ARGS(&pShellBrowser)))) 
         { 
          IShellView* pShellView; 
          if(SUCCEEDED(pShellBrowser->QueryActiveShellView(&pShellView))) 
          { 
           pShellView->Refresh(); 
           pShellView->Release(); 
          } 
         } 
        } 
       } 

       SysFreeString(LocationURL); 
      } 
      pFolder->Release(); 
      pFolder = NULL; 
     } 
    } 

    CoUninitialize(); 
} 

Я заметил, что когда моя программа делает это обновление регулярно медленно увеличивается в размерах и UMDH показал мне, что я, кажется, утечка pFolder и pShellWindow экземпляров каждый раз это выполняется. Я не могу понять, почему на земле это происходит, поскольку, насколько я могу судить, они выпущены должным образом. Может ли кто-нибудь увидеть то, что мне не хватает?

+1

Вы можете заменить IDispatch & IShellView на CComPtrs, BSTR на _bstr_t и VARIANT на _variant_t (comutil.h), таким образом, вы будете уверены, что ничего не утечка. –

ответ

4

Выпускаете pShellWindows после CoUninitialize, что является неправильным.

Остальные интерфейсы, кажется, выпущены отлично. Обратите внимание, что вы можете улучшить чистоту и удобочитаемость значительно, используя CComQIPtr вместо QueryInterface, а не используя необработанные указатели (BSTR, IFoo*) и замените их на интеллектуальные самовыравнивающиеся обертки.

pFolder может быть утечка, если Item звонок успешно, но возвращает код, отличный от S_OK. Опять же, использование CComPtr<IFolder> вместо IFolder* немедленно устранит эту проблему, даже не привлекая к ней никакого внимания.

+0

Спасибо, не могу поверить, что я не заметил проблему с pShellWindows ;-) – Benj

4
CoInitialize(NULL); 

Существует несколько проблем с этим утверждением. @Roman объяснил, как вы можете протекать путем uninitializing слишком рано. Но это также будет идти плохо в более чем одним способом, в квартире состояние нити действительно большое дело в COM:

  • Вы не проверять возвращаемое значение CoInitialize(). Это взорвет клиентское приложение, которое вызывает эту функцию, если оно уже вызвало CoInitializeEx() и выбранную MTA вместо STA. Это приведет к ошибке CoInitialize(), вы не сможете изменить состояние потока после его совершения. Ваш вызов CoUninitialize() приведет к удалению клиентского приложения в smithhereen, что приведет к сбою всех последующих COM-вызовов.

  • Выбор STA также требует, чтобы вы реализовали договор для однопоточной квартиры. В котором говорится, что вы никогда не блокируете поток, вы в порядке с этим. И, что вы накачиваете контур сообщения. Цикл сообщений имеет решающее значение для маршрутизации вызовов в однопоточную квартиру. Вы не согласны с этим, и вы не можете разумно обеспечить, чтобы в этом позаботились об этом. Особенно важно для интерфейсов оболочки, большинство из них не являются потокобезопасными. Следствием не перекачки является взаимоблокировка. Вам может уйти с не накачкой, это не гарантированный тупик. Здесь вы получите немного свободы, поскольку это, вероятно, интерфейсы вне процесса.

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

+0

В этом случае функция всегда вызывается созданным потоком, который был создан для обработки сообщения о трубопроводе, которое должно смягчить вашу первую точку (хотя я все равно проверю возвращаемое значение). Ваш второй вопрос действительно вызывает некоторую озабоченность, могу ли я смягчить это, просто используя многопоточную модель? – Benj

+0

В MTA нет бесплатного обеда, вы оставите его до другого кода, чтобы позаботиться о том, чтобы вызвать небезопасный код в потокобезопасном режиме. Лучше взять этого быка за рога. Я просто говорю вам, что может пойти не так, вы поймете, что не так, когда вы видите тупик кода. –

Смежные вопросы