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.
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;