Reputation: 601
I want to delete a file stored in an USB flashdrive (actually an android device's sd card).
I ask the user to point the app's folder inside the sd card, and i hold a Shell32.Folder
object pointing to it.
I can iterate between the files (FolderItem
objects), but how can i delete a file using Shell32
classes?
Usual File.Delete(filePath)
does not work, since the FolderItem.Path
is a BSTR data type, so maybe the key is to convert from one type to another, but i couldn't find a way to do this.
Any ideas?
EDIT 1:
FolderItem.Path
data:
"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_04e8&pid_6860&ms_comp_mtp>-p5100#7&392be4e4&0&0000#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,SECZ9519043CHOHB,12530364416}\{015C008D-013D-0145-D300-D300CB009500}\{015C00EE-013D-0145-0201-37012C010901}\{025901D2-029D-020F-DE01-FE010D02A601}"
This is not a valid path for File.Delete
. Any ideas on how to convert that?
EDIT 2:
Method that opens the browse folder window, so the user can point out the app directory, inside his android device's SD card, so i can iterate with folders and files, and sync some data with the server. Done this way due to problems between Win8 and Shell32:
public Shell32.Folder GetShell32NameSpace(Object folder)
{
Type shellAppType = Type.GetTypeFromProgID("Shell.Application");
Object shell = Activator.CreateInstance(shellAppType);
return (Shell32.Folder)shellAppType.InvokeMember("NameSpace", System.Reflection.BindingFlags.InvokeMethod, null, shell, new object[] { folder });
}
Using the method above, to get the Folder:
IntPtr windowHandle = new WindowInteropHelper(this).Handle;
Folder androidPath = BrowseForFolder(windowHandle.ToInt32(), "App's data folder", 0, 0);
I create and copy a file into the app's 'data' folder, so the device can recognize a syncing action, tell the user, and close the app:
byte[] data = new UTF8Encoding(true).GetBytes("sync_cable");
if (androidPath != null)
{
foreach (FolderItem dir in androidPath.Items())
{
if (dir.IsFolder && dir.Name == "data")
{
Folder dataFolder = GetShell32NameSpace(dir.Path);
if (dataFolder != null)
{
string tempPath = Path.GetTempPath();
string path = Path.Combine(tempPath, flagFileName);
File.WriteAllBytes(path, data);
Folder localPath = GetShell32NameSpace(tempPath);
if (localPath != null)
{
foreach (FolderItem file in localPath.Items())
{
if (file.Name.Contains(flagFileName))
{
dataFolder.CopyHere(file);
break;
}
}
}
}
break;
}
}
}
After the sync, i want to delete the file, so the app can function normally:
foreach (FolderItem file in dataFolder.Items())
{
if (file.Name.Contains(flagFileName))
{
// THIS THROWS AN 'INVALID PATH' EXCEPTION
// FileInfo fi = new FileInfo(file.Path);
// fi.Delete();
// THIS ALSO THROWS AN 'INVALID PATH' EXCEPTION
// File.Delete(file.Path);
break;
}
}
As mentioned in EDIT 1, file.Path
of the file i want to delete, has the following format:
"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_04e8&pid_6860&ms_comp_mtp>-p5100#7&392be4e4&0&0000#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,SECZ9519043CHOHB,12530364416}\{015C008D-013D-0145-D300-D300CB009500}\{015C00EE-013D-0145-0201-37012C010901}\{025901D2-029D-020F-DE01-FE010D02A601}"
EDIT 3:
As suggested here, i tried using P/Invoke to delete the file, with no success.
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeleteFile(string lpFileName);
Calling the method:
foreach (FolderItem file in dataFolder.Items())
{
if (file.Name.Contains(flagFileName))
{
// ...
bool deleted = DeleteFile(file.Path);
// ...
}
}
The method returns false, and the file is not deleted. I looked in the Event Viewer for a clue about what happened, but found nothing.
Upvotes: 5
Views: 1737
Reputation: 173
The guid prefix ("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}") is the standard junction point for MyComputer (see https://msdn.microsoft.com/en-us/library/windows/desktop/cc144096(v=vs.85).aspx).
I suspect the file cannot be deleted using such methods as the shell API DeleteFile because it is not in the file system (you can check it using FolderItem.IsFileSystem) because the android device is connected using MTP.
I have been able to delete such files using FolderItem.InvokeVerb("Delete"). This produces a confirmation dialog which can be dismissed using some version of SendKeys (for example freeware Nirsoft's Nircmd.exe). The following is a VBA sample:
Private Sub SampleDelete()
Const sFolder = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_054c&pid_04cb#10fbd475671683#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,00000000000000000000000005671683,7513636864}\{00000007-0000-0000-0000-000000000000}\{000057F1-0000-0000-66A5-884D99020600}"
Const sFileName = "test.txt"
' requires reference to Shell32.dll
Dim oShell As New Shell32.Shell
Dim oFolder As Shell32.Folder
Dim oFile As Shell32.FolderItem
Set oFolder = oShell.Namespace(sFolder)
If Not oFolder Is Nothing Then
Set oFile = oFolder.ParseName(sFileName)
If Not oFile Is Nothing Then
Debug.Print "File system? " & oFile.IsFileSystem
' dismiss the confirmation dialog
SendKeys "~"
' Alternatively use an external function, like this freeware utility
' Shell "nircmd.exe sendkey enter press", vbHide
oFile.InvokeVerb "Delete"
Else
Debug.Print "File not found"
End If
Else
Debug.Print "Folder not found"
End If
Set oShell = Nothing
Set oFolder = Nothing
Set oFile = Nothing
End Sub
Upvotes: 1
Reputation: 388
The part of the path which looks like "\?\" tells you that it's a long path. Sadly the CLR cannot handle long paths (it's limited to MAX_PATH = 260 nonsense). I believe you can use the WinAPI's DeleteFile to accomplish what you want.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363915(v=vs.85).aspx
Use PInvoke and you'll be all set.
http://pinvoke.net/default.aspx/kernel32/DeleteFile.html?diff=y
Upvotes: 0