Can I allow a user to delete a file, under Windows, that is in use by my application?
In my scenario I have a "quick add" directory that is monitored by my application. When it sees a new image show up it creates a new slide to display in an automated slide show. I would also like to allow my users to delete (and/or rename) a file from my "quick add" directory, and remove it from the slide show.
Is there a way I can flag the file that notifies Windows that I'm okay for it to remove the file while my application is using it?
Is there a way I can flag the file that notifies Windows that I'm okay for it to remove the file while my application is using it?
Yes. In Win32 this is dwShareMode passed to CreateFile(). This is a bitfield of what you would like to permit another process to do. The bit you are looking for is FILE_SHARE_DELETE which allows a delete or a rename while open. However, for the most polite behavior I would recommend including all 3, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE.[1]
Since you're asking about C# and not Win32, in the .NET world these are included in the FileShare enumeration which you can pass when opening a file, eg. in File.Open.
Note that these flags don't let you allow a rename of a file's parent directory while it is opened by name. That will fail regardless of sharing due to limitations in the kernel (technically in ntfs.sys IIRC).
Footnote
1: Editorial comment: It is a shame that passing 0 (which many people do without thinking) happens to be the least permissive option, or that more people writing code on Windows don't realize what this parameter does and pass these three flags.
If you call a Delete() or Rename() method onto the Control that is using the file, you can remove it from the PictureBox before it deletes or renames the file.
There shouldn't be much of an issue with doing multiples. With a Checkbox on the Control, you just check each Control to see if that property is true, then call the appropriate method.
Related
I am working on a Version Control/File Sync System for Windows. It would be great to have a checkbox at the bottom of the classical save file dialog with the option to check/uncheck for my file versioning.
Is it possible to listen for opened save file dialogs by any program (word etc.) and replace/override that dialog with a customized one (with an additional checkbox)?
If the checkbox is checked, another window should pop-up where the user could enter some additional metadata. After that the data is stored in a local database.
I already worked with the approach by dmihailescu (link provided) but it's very complex and I do not know how to modify that example to listen for opened save file dialogs by other programs.
http://www.codeproject.com/Articles/19566/Extend-OpenFileDialog-and-SaveFileDialog-the-easy?msg=4779306#xx4779306xx
Another approach is to use the FileSystemWatcher but that's very expensive to watch the whole system and it's not very comfortable because the user has to be asked for any created file if he/she wants to version control it.
I hope someone could help me to solve that problem or has some additional tips / approaches.
Thank you.
Edit: Use-case
A user has to write a documentation and creates a new word-doc. When he/she clicks the Save as menu entry of word, my customized save file dialog should pop-up with a checkbox at the bottom, if this file should be versioned or not. If the checkbox is "active" a new window should appear where the user could enter additional metadata. After that the data should be stored in local database.
In my case, only the metadata (like the path etc.) should be stored in the database. Let's suppose a user stores the same file in two different directotries (one file is "older" and one file is the current one). If the user opens an older version of this file, my system should recognize that a "newer" one is already stored in another place and synchronize those files.
That should just be a very easy example.
You have two pieces of functionality: save and version-control. Both of the tasks are actually rather complicated. Therefore you shouldn't mix them. You better off using standard Windows API to save file and do not change that. Think about how you'd support several different Windows releases and how painful that would be.
I assume you have your own UI, and do not integrate with, say, Windows Explorer (like Tortoise Svn or Dropbox). In this case you can do version-control magic first and then just save the end file using standard API.
If you do integrate with Windows Explorer, I suggest you to have a look at Tortoise svn source code.
I have an application that works weirdly: the setup process copies the files to a temp folder, then checks a few things, and if everything is ok, moves the files to the final folder.
The problem is that the installer creates the shortcuts before the files are moved.
The result is that on the start menu (the one with the tiles), the icon is the "default sortcut" one.
I have tried to force the refresh of the system using this link (broadcast a WM_SETTINGCHANGE message) but it doesn't seem to work for the Windows 8 start menu.
Even rebooting the OS doesn't seem to refresh the icon, the only thing that works is to reinstall the soft on top of itself.
How can I force the icons refresh for the Win8 start menu ?
Thanks
First off, you don't tell us why your install process needs to work the way that it does. I agree that's weird, but I assume you have a good reason for doing it that way. If not, I suggest starting there and fixing the installer rather than putting band-aids on individual problems. You're bound to run into other problems later, and the root fix is bound to be much simpler and easier to maintain than a bunch of band-aids.
Anyway, if you must go down this path… The reason that broadcasting a WM_SETTINGCHANGE message doesn't work is because this doesn't have anything to do with icons. Those are managed separately by Explorer and don't get rebuilt unless you delete its icon cache. That, naturally, prompts it to rebuild it. It's a common troubleshooting technique for end users, but it's not something you want to do programmatically. Talk about an ugly hack. And altering the global state to solve a local problem.
Besides, if rebooting the OS doesn't work, you know it's not as simple as you make it sound in your question: a property in need of a refresh. The reason that reinstalling on top of the existing installation works is because when the shortcut gets created in the beginning, its target executable already exists in the expected place (put there by the previous installation) with a valid icon.
What I recommend doing is writing some code to change the icon of the existing shortcut. Make sure that you execute it after you've copied the executable file to its final destination. The method that allows you to do that is IShellLink::SetIconLocation, which takes two parameters: a path to the icon (this would be the path to your executable file), and the index of the icon (this would probably be 0 assuming that the icon you want is the first and only one contained in the executable).
Of course, in order to call SetIconLocation, you're going to have to obtain an object representing your shortcut that implements IShellLink. This is a COM interface, which I don't believe is wrapped anywhere by the .NET Framework. General information on creating shortcuts from C# is available in the answers to this question. More specifically, there's a link to this wrapper class that you can use to do most of the dirty work. I don't think it contains a method for setting/changing the icon, but that can be trivially added.
Alternatively, you can get at these same properties using the Windows Scripting Host (WSH) wrapper, WshShortcut. It has an IconLocation property that works much the same way except that it takes only a single string argument, with the index delimited from the path by a comma: myApp.exe, 0. It's not particularly well documented (best I can find), but to get an existing shortcut, you just use the CreateShortcut method and specify the path to the existing shortcut. For example:
public void SetShortcutIcon(string shortcutPath, string iconPath, int iconIndex)
{
// Note: no error checking is performed for the parameters!
// This is not production-ready code!
// If a shortcut does not exist at the specified path, you should
// create a new one instead.
// If iconPath does not specify a valid executable file, you should
// set a default icon or perhaps abort.
IWshRuntimeLibrary.WshShell wsh = new IWshRuntimeLibrary.WshShell();
IWshRuntimeLibrary.IWshShortcut shortcut = wsh.CreateShortcut(shortcutPath);
shortcut.IconLocation = String.Format("{0}, {1}", iconPath, iconIndex);
shortcut.Save();
}
Note that in order for the above code to compile, you will also need to add a reference to the Windows Script Host Object Model to your application. To do this, right-click on the "References" folder in the Solution Explorer, click the "COM" tab, and find "Windows Script Host Object Model" in the list.
I just tested this and it works; the effect is instant.
I have a Windows Form application and I use a custom control that allows users to select and save image. However I need to insert some restrictions. The easy one was to select only jpg files but now I need to restrict the users to be able to see and select only jpg images with certain pattern in the name and if possible (I think I've seen this implemented in other windows applications) I want this pattern to stay in the File Name field and the user to not be able to delete it.
what I have done till now :
I have the restriction set:
fileNameFilter = "All files (*.jpg)|" + ImageNameFilter + "*.jpg";
openFileDialog1.Filter = fileNameFilter;
I can show the user what pattern he needs to look for:
openFileDialog1.FileName = fileNameFilter;
However there are two things that I still can't accomplish. Here is a print screen to make it clear:
First - the pattern is shown but I can delete it when it's made like this and I want if it's possible the File name field to be Read only or in other words the user should not be able to delete what I have put there.
Second - this is the list with previously opened files even though the file don't match the name restrictions/filters the user is still able to select form the list and save that file. I need, again if possible either to clean this list when the File Dialog is opened or somehow to stop the user from being able to save this file but i think the second will require too much extra business logic so I prefer just to clean the list.
Trying to control rigidly what's shown in a file dialog through a filter or a file name pattern is not going to work. The user can always type their own pattern into the file name edit box.
What you need to do is use the file dialog's facilities for controlling what objects are displayed. Unfortunately the C# wrapper doesn't expose this functionality that is offered by the underlying Win32 controls.
If you need to support XP, then you need to listen for the CDN_INCLUDEITEM notification. This is sent for each item in the folder. You therefore get the opportunity to either allow or deny the inclusion of each item.
For the dialogs used in Vista and later it's different. These dialogs use IFileDialog. You need to call the SetFilter method to add a filter. That filter is your implementation of IShellItemFilter which again controls inclusion using the IncludeItem method.
It's going to be a bit messy to make all this happen from C#, but this is the correct way to do what you ask. Once you do this, there's no need to even think about trying to make the file name edit box read-only. Because the dialog will only offer up the items that you have allowed to be included.
No.
Two solutions: check the filename after Open-click (which you should do anyway), or create your own control that displays files that do match your filename pattern.
I have a few questions related:
1) Is possible to make my program change filetype association but only when is running? Do you see anything wrong with this behavior?
2) The other option that I'm seeing is to let users decide to open with my application or restore default association ... something like: "capture all .lala files" or "restore .lala association". How can I do this? What do you think that is the best approach?
Regarding file associations, I've wrote an answer earlier that at least covers the "How".
This should also point you to the right direction how to handle backup and restore. With direct registry access through c#, there will be no need to use .reg files, so you are free to back up the previous value however you like in your app, and also restore it from there.
The key question here is: Should you change file associations randomly? At least asking the user up-front would obviously be necessary (as you also indicated).
Furthermore, Vista users with UAC enabled, or non-privileged users of other Windows versions may not have the required permission to change global file associations. The (un)installation procedure of your program may be the only place where this can succeed.
EDIT
As Franci Penov indicated in his answer, there is a way to change local file associations on a per-user basis, even for non-admins (that's why I spoke of "global associations" in the previous paragraph). He also mentioned mentioned why going there is not overly advisable.
You can implement an "on the fly" file association change by associating a small executable with that file extension that upon start will check if your main application is running and pass the file name to it or if it's not running it'll invoke the "regular" associated application.
The main advantage of this approach is that you need to muck with the registry only once.
The main drawbacks of this approach are:
you need a helper process
the application that "owns" these file extensions can detect the change and complain to the user, prompting "repair" thus getting you out of the picture.
Alternatively, you could change the file association upon your main program start. This will work even for non-admin users. while file associations are stored in HKEY_CLASSES_ROOT, there's a small trick - HKCR is actually a map of both HKEY_LOCAL_MACHINE\SOFTWARE\Classes and HKEY_CURRENT_USER\SOFTWARE\Classes. Thus, you can temporarily register the file extension for the current user in HKCU and "shadow" the original association from HKLM.
Of course, I would advise against this approach though, as it takes just one crash in your application to make that association permanent and since very few applications know how to deal with file associations in HKCU, chances are it'll be an unrecoverable situation for the original application.
It can probably be done but I think it would end up being cumbersome. All file type associations are stored in the registry so you would have to write/revert registry entries every time your app starts and stops. Also, depending on how frequently you do it the new associations may not be picked up in Windows explorer immediately.
The associations are listed under HKEY_CLASSES_ROOT in the registry and can be mapped a whole myriad of ways (mime types/progIDs/etc).
Many apps I have seen ask if you want to associate certain file types with the application during install time, and give you the ability to opt-out and leave the current settings.
I don't think I'd recommend "on the fly" file type associations
1) you get to define the file types that are in the Open Dialog file type droplist.
Outside of that, it's possible to change the filetype default on application open, and then replace during application close, as file type association are just a registry setting.
As for wrong, I wouldn't. First reason is that it's not the standard behavior of applications. The second reason is that if your application or PC exits unexpectedly, you run the risk of not returning the association to it's original setting.
2) Windows by default allows user to choose these options utilizing the right-click and the "open with" command.
Is there any way, in any language, to hook my program when a user renames a file?
For example:
A user renames a file and presses enter (or clicks away) to confirm the rename action. BEFORE the file is actually renamed, my program "listens" to this event and pops up a message saying "Are you sure you want to rename C:\test\file.txt to C:\test\test.txt?".
I'm thinking/hoping this is possible with C++, C# or .NET.. But I don't have any clue where to look for.
You can probably solve this by using the FileSystemWatcher class in .NET framework.
From the class remarks:
You can watch for renaming, deletion,
or creation of files or directories.
For example, to watch for renaming of
text files, set the Filter property to
"*.txt" and call the WaitForChanged
method with a Renamed specified for
its parameter.
My guess is that this is not possible, I did find this which is for monitoring operations (including rename) on a folder, but there does not appear to be a similar method for files.
#Richard, FileSystemWatcher is good if you only need to monitor changes, but he needs to interrupt them which it cannot do.
IFileOperationProgressSink.PreRenameItem is the closest supported thing I know of. Unfortunately, it's not a hook into Explorer - so you can only use it for your own IFileOperation actions. Depending on your needs, you can write a shell extension to do your own ConfirmRename (or something), and branch from there.
Otherwise, you're looking at hooking SHFileOperation, I think. This would have to be done in unmanaged code, as you'll be loaded into Explorer.exe. For Vista, this has been changed to IFileOperation - which probably means you'll have to hook the creation of it and pass out your mock.
Personally, I think since you're talking a rename, wilhelmtell's idea of confirming after the change, and undoing it if necessary is the best idea.