How to close Windows Explorer windows with opened folders from a certain drive

若如初见. 提交于 2019-12-07 16:55:29

问题


I'm writing a small app that will allow a user to eject (or safely remove) a USB drive. My app works fine, except the situation when a folder on the USB drive (or several folders) are opened in Windows Explorer. In that case the eject function fails as the drive appears to be locked.

So I'm curious, since the user is issuing a command through my app to eject the USB drive, is there any way to make Explorer close those open windows from the USB drive?

PS. Note that I don't want to close all processes belonging to the Windows Explorer, but only the ones that opened folders on a specific drive.


回答1:


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;



回答2:


Here's @DenisAnisimov's method re-written for 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;
}


来源:https://stackoverflow.com/questions/23965895/how-to-close-windows-explorer-windows-with-opened-folders-from-a-certain-drive

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!