如何从特定驱动器中关闭已打开文件夹的Windows资源管理器窗口

时间:2014-05-31 02:43:40

标签: c++ windows winapi windows-shell windows-explorer

我正在编写一个小应用程序,允许用户弹出(或安全删除)USB驱动器。我的应用程序工作正常,除了在Windows资源管理器中打开USB驱动器(或多个文件夹)上的文件夹的情况。在这种情况下,弹出功能会因驱动器似乎被锁定而失败。

所以我很好奇,因为用户通过我的应用程序发出命令以弹出USB驱动器,有没有办法让Explorer从USB驱动器关闭那些打开的窗口?

PS。请注意,我不想关闭属于Windows资源管理器的所有进程,而只关闭在特定驱动器上打开文件夹的进程。

2 个答案:

答案 0 :(得分:3)

procedure ProcessExplorerWindows(ADriveLetter: WideChar; AClose: Boolean);
var
  ShellWindows: IShellWindows;
  i: Integer;
  Dispatch: IDispatch;
  WebBrowser2: IWebBrowser2;
  ServiceProvider: IServiceProvider;
  ShellBrowser: IShellBrowser;
  ShellView: IShellView;
  FolderView: IFolderView;
  PersistFolder2: IPersistFolder2;
  ItemIDList: PItemIDList;
  ShellFolder: IShellFolder;
  ChildItem: PItemIDList;
  Attr: DWORD;
  StrRet: TStrRet;
  FileName: UnicodeString;
  DesktopItemIDList: PItemIDList;
begin
  OleCheck(CoCreateInstance(CLASS_ShellWindows, nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IShellWindows, ShellWindows));
  try
    for i := ShellWindows.Count - 1 downto 0 do
      begin
        Dispatch := ShellWindows.Item(i);
        try
          OleCheck(Dispatch.QueryInterface(IWebBrowser2, WebBrowser2));
          try
            OleCheck(Dispatch.QueryInterface(IServiceProvider, ServiceProvider));
            try
              OleCheck(ServiceProvider.QueryService(SID_STopLevelBrowser, IShellBrowser, ShellBrowser));
              try
                OleCheck(ShellBrowser.QueryActiveShellView(ShellView));
                try
                  OleCheck(ShellView.QueryInterface(IFolderView, FolderView));
                  try
                    OleCheck(FolderView.GetFolder(IPersistFolder2, PersistFolder2));
                    try
                      OleCheck(PersistFolder2.GetCurFolder(ItemIDList));
                      try
                        OleCheck(SHBindToParent(ItemIDList, IShellFolder, Pointer(ShellFolder), ChildItem));
                        try
                          Attr := SFGAO_FILESYSTEM;
                          OleCheck(ShellFolder.GetAttributesOf(1, ChildItem, Attr));
                          if Attr and SFGAO_FILESYSTEM = SFGAO_FILESYSTEM then
                            begin
                              OleCheck(ShellFolder.GetDisplayNameOf(ChildItem, SHGDN_FORPARSING, StrRet));
                              FileName := '';
                              case StrRet.uType of
                                STRRET_WSTR:
                                  begin
                                    FileName := StrRet.pOleStr;
                                    CoTaskMemFree(StrRet.pOleStr);
                                  end;
                                STRRET_OFFSET:
                                  if Assigned(ChildItem) then
                                    begin
                                      Inc(PByte(ChildItem), StrRet.uOffset);
                                      FileName := UnicodeString(PAnsiChar(ChildItem));
                                    end;
                                STRRET_CSTR:
                                  FileName := UnicodeString(AnsiString(StrRet.cStr));
                              end;
                              if ExtractFileDrive(FileName) = ADriveLetter + ':' then
                                if AClose then
                                  WebBrowser2.Quit
                                else
                                  begin
                                    SHGetFolderLocation(0, CSIDL_DESKTOP, 0, 0, DesktopItemIDList);
                                    try
                                      OleCheck(ShellBrowser.BrowseObject(DesktopItemIDList, SBSP_SAMEBROWSER or SBSP_DEFMODE or SBSP_ABSOLUTE));
                                    finally
                                      CoTaskMemFree(DesktopItemIDList);
                                    end;
                                  end;
                            end;
                        finally
                          ShellFolder := nil;
                        end;
                      finally
                        CoTaskMemFree(ItemIDList);
                      end;
                    finally
                      PersistFolder2 := nil
                    end;
                  finally
                    FolderView := nil;
                  end;
                finally
                  ShellView := nil;
                end;
              finally
                ShellBrowser := nil;
              end;
            finally
              ServiceProvider := nil;
            end;
          finally
            WebBrowser2 := nil;
          end;
        finally
          Dispatch := nil;
        end;
      end;
  finally
    ShellWindows := nil;
  end;
end;

答案 1 :(得分:2)

这里为DenisAnisimov为C ++重写的方法:

HRESULT CloseWindowsExplorerWindowsForDrive(LPCTSTR pStrPath)
{
    //Closes all Windows Explorer windows for a specific drive
    //'pStrPath' = path somewhere on the drive
    //RETURN:
    //      = S_OK if done
    CoInitialize(NULL);

    HRESULT hr;

    TCHAR buffVolPath[MAX_PATH];
    buffVolPath[0] = 0;
    if(GetVolumePathName(pStrPath, buffVolPath, MAX_PATH))
    {
        int nLnVolPath = lstrlen(buffVolPath);

        IShellWindows* pISW = NULL;

        hr = CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
            IID_IShellWindows, (void**) &pISW);
        if (SUCCEEDED(hr))
        {
            long nCount;
            if(SUCCEEDED(hr = pISW->get_Count(&nCount)))
            {
                for(int i = nCount - 1; i >= 0; i--)
                {
                    CComPtr<IDispatch> pIDisp;
                    CComVariant v_i(i);
                    if(SUCCEEDED(hr = pISW->Item(v_i, &pIDisp)))
                    {
                        CComPtr<IWebBrowser2> pIWB2;
                        if(SUCCEEDED(pIDisp->QueryInterface(IID_IWebBrowser2, (void**)&pIWB2)))
                        {
                            CComPtr<IServiceProvider> pISP;
                            if(SUCCEEDED(pIDisp->QueryInterface(IID_IServiceProvider, (void**)&pISP)))
                            {
                                CComPtr<IShellBrowser> pIShBrswr;
                                if(SUCCEEDED(hr= pISP->QueryService(SID_STopLevelBrowser, IID_IShellBrowser, (void**)&pIShBrswr)))
                                {
                                    CComPtr<IShellView> pIShView;
                                    if(SUCCEEDED(hr = pIShBrswr->QueryActiveShellView(&pIShView)))
                                    {
                                        CComPtr<IFolderView> pIFV;
                                        if(SUCCEEDED(hr = pIShView->QueryInterface(IID_IFolderView, (void**)&pIFV)))
                                        {
                                            CComPtr<IPersistFolder2> pIPF2;
                                            if(SUCCEEDED(hr = pIFV->GetFolder(IID_IPersistFolder2, (void**)&pIPF2)))
                                            {
                                                LPITEMIDLIST pidlFolder = NULL;
                                                if(SUCCEEDED(hr = pIPF2->GetCurFolder(&pidlFolder)))
                                                {
                                                    LPCITEMIDLIST pidlChild = NULL;
                                                    CComPtr<IShellFolder> pIShFldr;
                                                    if(SUCCEEDED(::SHBindToParent(pidlFolder, IID_IShellFolder, (void**)&pIShFldr, &pidlChild)))
                                                    {
                                                        ULONG attrs = SFGAO_FILESYSTEM;
                                                        if(SUCCEEDED(hr = pIShFldr->GetAttributesOf(1, &pidlChild, &attrs)))
                                                        {
                                                            if(attrs & SFGAO_FILESYSTEM)
                                                            {
                                                                STRRET srt;
                                                                if(SUCCEEDED(hr = pIShFldr->GetDisplayNameOf(pidlChild, SHGDN_FORPARSING, &srt)))
                                                                {
                                                                    LPWSTR pStrFileName = NULL;
                                                                    if(SUCCEEDED(hr = StrRetToStr(&srt, pidlChild, &pStrFileName)))
                                                                    {
                                                                        //Compare to our path
                                                                        if(lstrlen(pStrFileName) >= nLnVolPath &&
                                                                            ::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
                                                                            buffVolPath, nLnVolPath,
                                                                            pStrFileName, nLnVolPath) == CSTR_EQUAL)
                                                                        {
                                                                            //Close it
                                                                            hr = pIWB2->Quit();
                                                                        }
                                                                    }

                                                                    if(pStrFileName)
                                                                    {
                                                                        CoTaskMemFree(pStrFileName);
                                                                        pStrFileName = NULL;
                                                                    }

                                                                    //Free mem (if StrRetToStr() hasn't done it)
                                                                    if(srt.pOleStr)
                                                                    {
                                                                        CoTaskMemFree(srt.pOleStr);
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }

                                                //No need to free pidlChild!
                                                }

                                                if(pidlFolder)
                                                {
                                                    CoTaskMemFree(pidlFolder);
                                                    pidlFolder = NULL;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            pISW->Release();
        }
    }
    else
        hr = E_INVALIDARG;

    CoUninitialize();

    return hr;
}