How can you detect when files are dropped into Windows Explorer? - c#

I have a WinForms app that has a TreeView. The user can drag files from WindowsExplorer to the TreeView, and then they can drag the files back into WindowsExplorer which in affect copies the files to wherever the files were dropped. What I'm trying to do is, if the files already exist in the directory where the files are being dropped, I want to rename the files/folders being copied in ahead of time, so that there's no collision.
Here's how I'm copying files into WindowsExplorer. On the treeView's ItemDrag, I loop through the nodes of the selected node, and then package that into an array. Then, I use this code:
var dataObject = new DataObject(DataFormats.FileDrop, files.ToArray());
dataObject.SetData(DataFormats.StringFormat, dataObject);
DoDragDrop(dataObject, DragDropEffects.Copy);
This works well, but once it ships off to Windows Explorer, it's out of my hands. How can I find out when and where the files are being copied TO and intercept that to make changes? Is this possible?

Explorer Drag & Drop is an excellent article doing what you are trying to achieve.
EDIT2: It seems that there's a C++ article available for the same on CodeProject. But I was unable to find a way of how to do it using C#.

AFAIK, there is no way to know drop target (in your case destination folder). You can look into CFSTR_FILENAMEMAP shell clipboard format, but still in this case you can only provide name mappings before (or in process) of drag-n-drop.
Also note, that default DataObject in .net has limited shell support. So if you need to use mentioned above format, you need to write your own IDataObject implementation (or take someone's implementation, good example with lot shell drag-n-drop related stuff can be found here)

Instead of putting the file names into the dataobject, create a temporary file with a unique/easily distinguishable name and place that file name into the data object's drop list instead (That file could be empty or contain some information you might need). Use a FileSystemWatcher (watching an entire drive) to detect the drop (set the filter to the temporary file name, set IncludeSubDirectories to true, and set Path to root directory of drive to watch.) Initiate the DoDragDrop. Once the unique/easily distinguishable file is dropped, the FileSystemWatcher can tell you where it was dropped and you can do whatever you need to do (e.g. delete the dropped temporary file and replace with the ones you originally wanted to drop. It is a far-from-perfect solution but might help. Better still, it might give someone an idea to come up with a better one!)
One downside is that you don't really know in which drive someone might drop the file and you may have to set up a watcher for several drives. And if you miss a drive (or a network path) then problems .....! Remember to dispose of the watchers after the drop.
There has to be a better way though. e.g. consider when you drag a file from a zip folder. The file is only extracted after the drop.

i don't think that is possible.

Related

Hide copy source from VisualBasic CopyDirectory in C#

Using this namespace:
Microsoft.VisualBasic.FileIO;
I am copying a source folder from on our network to the user's computer using this line of code:
FileSystem.CopyDirectory(networkDir.FullName, localDir.FullName, UIOption.AllDialogs, UICancelOption.DoNothing);
This opens up that nice copy window we are all familiar with, which shows:
that my application is not hung up and is thinking.
how long the transfer will take.
Problem is that this window also shows the source and destination locations of the copy. I don't really want the user to see the IP and exact file path where the files are coming from.
I would like to avoid creating a big recursive foreach loop to make a directory copier, on top of having to provide an active UI that shows that the program is thinking. Are there any good workarounds or other solutions to achieve a directory copy without the source location being made public?
source location being made public
Do you control the source being downloaded from? If it's from a webserver you could make the whole thing ephemeral, and even use a hosts file entry to obfuscate the IP:
"Downloading from http://daves.server.honest/downloads/onetime/23i23i34248723084r/dir.zip"
Could be essentially useless to the 2nd person who tries to use the path.
Sadly if you're on a network drive rather than a webserver, your options are slightly more limited since it all has to be 'real' :/

Drag and Drop from ListView to Explorer [duplicate]

This question already has answers here:
Drag Drop from .NET application to Explorer
(2 answers)
Closed 7 years ago.
My goal is to able to drag an item from a ListView to Explorer. The way I'm trying to accomplish this is somewhat different though. From searching Google and around this site, I couldn't really find anything that would help me or pertained closely enough to what I'm trying to do. I can barely comprehend some of the examples because I don't understand enough about these drag and drop operations.
Specifically, the control that I'm trying to drag items from is a TreeListView from the ObjectListView library. The control is populated with nodes that represent the structure inside a archive-like compressed file. Entries are parsed into two different objects representing a file and a directory. Both of these models inherit an interface. When extracting these files normally, I use a Form that I instantiate with a collection of nodes and the target path that they will be extracted to as the parameters. It then takes care of extraction. This is so that I can show the overall and singular progress of each file.
Subscribing to the ItemDrag event, I know that I need to call DoDragDrop. When doing this, I need to be able to instantiate the extraction form only after the drop (when the user releases the mouse) into Explorer, and also be able to retrieve the path in which the items were dragged.
For some reason, this seems a lot more complicated than it should be. Any sort of advice or suggestions would be very helpful.
I'm not sure what format Explorer expects in the drag object, but this process might work for you.
When you begin the drag, pre-extract the selected files to some temp
directory
Build a DataObject which contains the paths of the files you have extracted in the format expected by Explorer
Use your DataObject in the DoDragDrop call
When the user drops on Explorer, the files should get copied from the temp directory to the drop target
Track all of your extracted files and cleanup when the application exists (id desired)
Hope this helps.
Edit (after some research):
I believe if you use
new DataObject(DataFormats.FileDrop, files)
where files is a string[] of the filenames to be copied (the ones you put in the temp directory), you shouold have the correct DataObject for implementation.
Haven't had a chance to write a prototype yet to test. Good Luck!

WPF file to file drag and drop

I would like to have a function for my application such that dragging any file in Windows Explorer to a file having the correct format for my application adds that first file to the second, like with WinZip, 7-zip etc. Example, if I drag a file onto another zip file, it initiates the default application for Zip (in my case 7-zip) and adds it to the zip archive I drop it onto.
I've tried searching for a way to do this on Google, but I don't know what this type of function would be called or the correct keywords I should use. Referencing drag and drop, shell extensions etc. all points me to dragging a file from the Shell into my application or vice versa which I know how to do. Can anyone point me in the direction of what I should be searching for, or even better has some example code/tutorial on how to achieve this?
Well, searching for Shell extensions was correct. There is a github project that makes it easy to create shell extensions in .Net: https://github.com/dwmkerr/sharpshell
One of them is a drop handler, and that is what you're looking for if I understand your question right. There are some tutorials on how to use SharpShell on CodeProject, this one specific for the drop handler: http://www.codeproject.com/Articles/529515/NET-Shell-Extensions-Shell-Drop-Handlers

Calculating and caching folder sizes

I have an idea for a C# program that works basically like the Windows Explorer. The aim is to display all files and folders, and to show specific information for each of them. One of the features I'm planning is to detect folder sizes which is something the Explorer cannot.
My idea for the algorithm is to cumulate the sizes of all files in the specific folder. However, I'm afraid of performance issues. For example, for displaying the sizes of all folders of C: I have to consider all the files on the whole drive. This will probably take a while and thus the calculation can't be done each time the user switches to a different folder or back.
So I'd like to cache some of the sizes. However, when files change, are added or removed, the cache data becomes outdated. But I do not want to monitor all file changes while the program is not running.
Is there any way I can find out if the cache is up-to-date, e.g. by retrieving some sort of checksum that doesn't require calculating all sizes again? Is there another memory and CPU-efficient way to find out if file sizes have changed since the last calculation? Or is there even another possibility?
Windows Explorer has the Folder size available (# files, size on disk etc) availble for the properties of any disk/folder. Directory Properties Example
As for writing a program, you can certainly use a recurisve DirectoryInfo.EnumerateFiles() to get all the files within a disk/folder.
As for monitoring, you can use the FileSystemWatcher class to monitor changes to any disk/folder.
To keep the cache up to date is going to be difficult because:
Depending on the Partition Formated Type [Fat, Fat32, NTFS, etc] you are limited to what each support.
Any new file (created date > cache date) means you still have to enumerate all the files to filter the list to new files.
Modified files (modified date > cache date) has the same issue.
Unless you use something VERY specific to the Formatted Type beyond what C# provides, updating a cache after the application launch will need to occur every time, and be very intense.
Windows Explorer is a pretty crafty program. It is filled with tricks that are designed to hide the fact that any file system is punishingly slow to iterate. The kind of tricks that I know about:
fake it. Show the folder hierarchy as a treeview and use the [+]
glyph to show that a folder has files or directories inside of it.
Even when it doesn't. That's visible, create an empty directory and
restart your machine. Note the [+] glyph, click it and notice that,
when forced to iterate the sub-directory, it smoothly change the [+]
glyph to a 'nothing there' glyph.
delay it. Harder to see, you need a subdirectory with a lot of
files. Explorer starts a background thread that iterates the
content of the folder. Once it figured it out, it smoothly changes
the status bar text.
tell me what happened. Explorer uses ReadDirectoryChangesW()
heavily. Wrapped in .NET by the FileSystemWatcher class. Key point
is that it gets a notification that something changed in the
subdirectory that the user is looking at. No polling required, that
would have horrible perf. Go back to bullet two.

How to know the next temp file to be created in windows?

I am by no means a programmer but currently am wondering if an application creates a temp file that windows names. For example the file it creates is tmp001, is there a way i can take that name tmp001 and ask windows to give me the next temp file it would create before it creates it.
Thanks,
Mike
There is no direct means to get to know the next temporary filename to be created.
For example, programmers use the System.IO.Path.GetTempFileName method, but one can add application-specific prefixes or suffixes in order to make it easier for the application to find its newly created files.
One can even choose to save this temporary file elsewhere than the system Temp folder.
You would need to define a "temp file" much more explicitly in order to answer this question with a "Yes". The problem is that a "temp file" is just something not meant to be kept. It could exist anywhere on the system and be created by a user, application, or service. This would make it nearly (or actually) impossible to answer your question with a "Yes".
If you constrain the definition of a temp file to just the files in the official temp folder (or a subfolder), you still have a problem if you're trying to catch names not generated by windows. Any app could produce a particularly named temp file in that folder, without Windows caring.
If you further constrain the definition to be only those files named by Windows, you might be able to get somewhere. But, does that really meet your needs?
After all of that, maybe it would be better to describe the problem you're trying to solve. There may be a much better (workable) solution that would address the issue.
Typically applications use the Win32 API GetTempFileName to get the temporary directory.
The process of how the temp file is generated is described there.
I'm not sure why you want this info, but perhaps you could for example register for directory changes via a Win32 API like ReadDirectoryChangesW or by using a mini filter driver.
This kind of code just cannot work reliably on a multi-tasking operating system. Another thread in another process might pre-empt yours and claim the file name you are hoping to create.
This is otherwise easy enough to work around, just name your own files instead of relying on Windows doing it for you. Do so in the AppData folder so you'll minimize the risk of another process messing it up.

Categories