2016-11-21 5 views
1

У меня есть расширение пространства имен в разработке, и я застрял, добавляя папку программно изнутри расширения. Что происходит визуально, нажатие кнопки панели инструментов, выбор пути к файлу, и этот файл является источником данных, из которого создаются виртуальные папки и файлы.Как добавить виртуальную папку (IShellFolder) в представление Проводника из расширения пространства имен?

Что я хочу делать, так как кнопка загрузки файла на панели инструментов находится в корне расширений пространства имен, для автоматической отображения новой виртуальной папки. Чтобы он появился, мне нужно щелкнуть древовидное представление или выйти из корня и обратно. Тогда папка присутствует.

Я исследовал эту проблему, и обычно, когда это происходит, люди используют SHChangeNotify. Я попробовал это, как в примере ниже, и использовал различные комбинации, такие как предоставление пути или pidl из корня расширения пространства имен, пример ниже, включая новую папку, которая должна быть там, с помощью pidl этого пути (с соответствующим флагом в SHChangeNotify) и все еще нет кубиков. Я также попробовал SHCNE_xxx, где xxx - флаг всех уведомлений. SHChangeNotify (SHCNE_UPDATEDIR, SHCNF_IDLIST, retPidl, 0);

Щелчок правой кнопкой мыши по области просмотра и выбирая обновление не вызывает появление папки.

В коде, который получает путь к папке, я вызвал BindToObject моей папки, а затем EnumObjects и Next, точки останова не пострадали. Когда я нажимаю на древовидную структуру или поднимаю папку и отступаю, все точки останова попадают. SHChangeNotify не вызывает точки останова.

Вид создается с помощью SHCreateShellFolderView в CreateViewObject так:

if (IID_IShellView == riid) { 
    SFV_CREATE csfv = {0}; 
    csfv.cbSize  = sizeof(SFV_CREATE); 
    hr    = QueryInterface(IID_PPV_ARGS(&csfv.pshf)); 
    if (SUCCEEDED(hr)) { 
     hr = CShellFolderView_CreateInstance(IID_PPV_ARGS(&csfv.psfvcb)); 
     if (SUCCEEDED(hr)) { 
      hr = SHCreateShellFolderView(&csfv, (IShellView**)ppv); 
      csfv.psfvcb->Release(); 
    m_hWnd = hwndOwner; 
     } 
     csfv.pshf->Release(); 
    } 
} 

в классе ShellVolderView, я поставил п.н. на флаги уведомления, и они никогда не попадают. Я прочитал, что для SFVM_UPDATEOBJECT требуется возвращение S_OK, поэтому я добавил это.

IFACEMETHODIMP CShellFolderView::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam) { 
    HRESULT hr = E_NOTIMPL; 
    switch(uMsg) { 
     case SFVM_GETSORTDEFAULTS: 
      wParam = (WPARAM)(int*)-1; 
      lParam = (LPARAM)(int*)Col::Size; 
      hr  = S_OK; 
      break; 
     case SFVM_GETNOTIFY: 
      *((LONG*)lParam) = SHCNE_ALLEVENTS; 
      hr     = S_OK; 
      break; 
    } 
    return hr; 
} 

* Редактирование: Добавление подозреваемого функции. Когда * ppidl имеет значение NULL, возвращается E_INVALIDARG.

STDMETHODIMP CShellFolder::ParseDisplayName(HWND hwnd, IBindCtx *pbc, LPWSTR pszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes) { 
    HRESULT hr = E_INVALIDARG; 

    if (pszDisplayName && *ppidl) { 
     WCHAR szNameComponent[MAX_SIZE] = {}; 
     PWSTR pszNext     = PathFindNextComponent(pszDisplayName); 
     if (pszNext && *pszNext) { 
      // unsure of max length, can't use StringCchLength for this 
      size_t len  = lstrlen(pszDisplayName); 
      size_t nextLen = 0; 
      StringCchLength(pszNext, MAX_SIZE, &nextLen); 
      hr = StringCchCopyN(szNameComponent, MAX_SIZE, pszDisplayName, len - nextLen); 
     } 
     else { 
      hr = StringCchCopy(szNameComponent, MAX_SIZE, pszDisplayName); 
     } 
     if (SUCCEEDED(hr)) { 
      PathRemoveBackslash(szNameComponent); 
      PIDLIST_RELATIVE pidlCurrent = NULL; 
      LPPIDLDATA child    = m_pPidlMgr->GetSubItemFromPidl((LPCITEMIDLIST)ppidl); 
      hr        = m_pPidlMgr->Create(&pidlCurrent, child); 
      if (SUCCEEDED(hr)) { 
       if (pszNext && *pszNext) { 
        IShellFolder *psf; 
        hr = BindToObject(pidlCurrent, pbc, IID_PPV_ARGS(&psf)); 
        if (SUCCEEDED(hr)) { 
         PIDLIST_RELATIVE pidlNext = NULL; 
         hr = psf->ParseDisplayName(hwnd, pbc, pszNext, pchEaten, &pidlNext, pdwAttributes); 
         if (SUCCEEDED(hr)) { 
          *ppidl = ILCombine(pidlCurrent, pidlNext); 
          ILFree(pidlNext); 
         } 
         psf->Release(); 
        } 
        ILFree(pidlCurrent); 
       } 
       else { 
        *ppidl = pidlCurrent; 
       } 
      } 
     } 
    } 
    return hr; 
} 

Какие шаги я должен предпринять, чтобы получить папку для программной разработки?

+0

SHCNE_UDPATEDIR говорит: "Эй, если кто-то смотрит на' thenewfoldername', они должны обновить." Но никто не смотрит на 'thenewfoldername', потому что его не существует. В документации говорится: «Если папка была создана, удалена или переименована, используйте SHCNE_MKDIR, SHCNE_RMDIR или SHCNE_RENAMEFOLDER соответственно». –

+0

Источник данных расширения пространства имен является древовидной структурой, отдельно от SHITEMIDLIST. После обновления дерева источника данных, чтобы добавить другую ветку от корня и правильно вызвать SHChangeNotify (спасибо), какие еще шаги я должен предпринять, чтобы получить/попросить Shell вызвать IShellFolder2 :: EnumObjects()? –

+1

Поднимите один SHCNE_MKDIR для каждого созданного каталога. Если вы создали под-подкаталог, то это означает, что он поднимает его дважды, один раз для каталога первого уровня и один раз для каталога второго уровня –

ответ

1

Попробуйте следующее:

SFVM_GETNOTIFY: 
    begin 
    PDWORD(ALParam)^ := SHCNE_ALLEVENTS; 
    Result := S_OK; 
    end; 
+0

В SFVM_GETNOTIFY я теперь устанавливаю флаг, как вы предлагали, и устанавливая pidl в lParam, но IShellFolder: EnumObjects и BindToObject получает вызов после выдачи SHChangeNotify. Но SFVM_FSNOTIFY теперь получает удар. В пользовательском интерфейсе изменений не происходит, папка не показывает w/out с помощью дерева или вверх и обратно в корневую папку. –

+0

Если вы используете DefShellView, вы можете попытаться удалить обработчики SFVM_UPDATEOBJECT, SFVM_QUERYFSNOTIFY, SFVM_ADDOBJECT и SFVM_FSNOTIFY. В случае этих значений просто верните E_NOTIMPL, потому что эти значения должны обрабатываться DefShellView. –

+0

Это имеет смысл. Я слепо сказал, что все в порядке, если ничего не делать в этих случаях. Спасибо за это. Я приближаюсь, но EnumObject по-прежнему не вызывается после отправки уведомления о событии через SHChangeNotify. Я думаю, что после вызова EnumObjects Explorer будет показывать новые данные, вызывая интерфейс Enumerator, а затем я могу создать SHITEMID. Есть идеи? –

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