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.
Related
Is it possible to create a C#.net (or a .bat) program that will automatically run upon access of a specific folder?
Thanks.
Windows 7/8/10: Not if you don't have a background process running that checks for the folder to be opened. So no, considering you want this to behave autonomously, I'm afraid not.
Windows XP: Yes, but let's not do that. This brings security issues and the only implementation I know of is the MS32DLL virus that would do this to partition roots.
EDIT: Based on your last comment (in particular the one that elaborates the context being data security), this is the wrong approach. There are multiple ways around this (think of any third party file browser, even DOS will work) and having this feature in Windows would leave it very vulnerable to attacks. Instead, you should read into applying NTFS permissions and file encryption.
I have a program that decrypts a zip file, extracts it to a secret location, and then runs a program in the extracted folder. I would like to ensure that no external program can copy the extract folder to another location (the secret folder is deleted upon program completion).
I have already eliminated Windows Explorer by making my decryption program a "always on top" program that deletes the secret folder if it is killed (by use of another hidden program that the decryption program starts). My concern is that another program could watch the process list, discover the folder location and perform the copy.
Is there a way to prevent programmatic copying of a directory, or if not, of a file?
Look at Directory.CreateDirectory(string,DirectorySecurity)
You'll need to create a DirectorySecurity object that encapsulates the desired permission set. The easiest way is to create a model directory owned by the process' userid with the desired permission sets (e.g., "Only I can traverse this directory or see or even open anything in it."). Once you've done that, use the DirectorySecurity constructor overload DirectorySecurity(String, AccessControlSections) to instantiate a DirectorySecurity object with identical permissions.
Another approach, of course, would be to create the same sort of "model directory" as above and create your "secret" working directory as a subdirectory of that, inheriting the parent's permission set.
As far as securely deleting the contents on disk, look at the question "Shredding files in .NET"
If the information is that sensitive, you should probably be decrypting it into memory rather than disk. But you should be aware that that's not secure either. The recent data breach Target's POS systems suffered was due to custom-designed malware harvesting plain-text credit card and other PCI/sensitive data from process memory.
Well for that purpose you need to set share mode. Not sure about C# solution, but as far as I know in C# you are able to use Win32, so you need to open files in that folder using CreateFile and set dwShareMode to zero.
Also if you want to delete all the stuff after program terminates, you can use FILE_FLAG_DELETE_ON_CLOSE flag.
So as I mentioned, not sure if it is easy to do this using C#, but you can always trust C++, it lets do the stuff in lower level.
The file system is always public, when run from a user context.
You could always attempt to extract the 'folder' to a binary stream - and create a raw, binary file on the file system, that would have no obvious meaning - e.g. make your own temporary "file system"
Short answer: you can't.
Do note that hiding a window / displaying a window always on top are very weak protections, it's really easy to change that from another process.
Also do note that you always can suspend processes instead of terminating them, so it's also easy to prevent any logic such as "if you're killed, then I do XXX" to execute
Best thing you could do is create a user account and restrict rights to read your files/directory to only this account. Of course, admin will still have access to it.
I'm not sure if the question's title makes sense, and I'm sorry if it doesn't; I didn't really know what to title it.. Anyway, is there a way to make your program track the viewing of a folder?
What I'm trying to achieve: Windows 7 Home Premium doesn't allow encryption. So, I made a folder inside my user directory, and set it to hidden. Although, you can easily find it by changing windows settings.. So, is there a way to make a program pull up a window if the user tries to access that certain folder?
I don't think you can detect the "opening" of a folder.
Instead, you may want to set a FileSystemWatcher to detect any file access to the files in that particular folder.
Hope this helps.
First of all, I have to wonder why you're not just setting an ACL on the directory to prevent access.
However, it sounds like you want to find when somebody is accessing a particular directory. To do this, you enable filesystem auditing, then set the audit ACL to generate audit entries for "List folder". This will cause entries to be generated in the Security Event Log whenever the directory is viewed.
Now you just have to write a program that watches the Security event log looking for entries indicating that somebody has listed the directory in question and take action as necessary.
Well, there is an article on code project describing how you can hook into windows system calls: http://www.codeproject.com/KB/system/hooksys.aspx - it's not simple though (and also not C#) and has the potential to screw with your system but if it might be a fun project to work on.
A simpler option would be: Use a 3rd party desktop encryption tool - not much programming involved here but it might do the job better than anything else.
Is there a reliable method to check if an application is run from somewhere beneath program files?
If the user installs the application to program files on local machine, we need to put writable files somewhere else to avoid virtualization on Vista and Win7. When installed to a network disk, though, we want to keep these files with the installation for shared access among users.
Today we do an string comparison between startup path and CSIDL_PROGRAM_FILES, but something tells me this is a very unreliable method.
Any smart solution out there?
Is there a 'IsRunningFromProtectedFolder( )'-api that I do not know about?
Are there any other folders giving the same problems as program files do?
This is not a terribly good idea, as a user can install it wherever they want to, and then the check might fail. Instead have a checkbox when the user installs the app, deciding if it is installed locally or on a server.
As you I also found problems dealing with UAC folder virtualization.I suggest a workaround, it seems that it should work.
It comes from the assumption that elevated processes always use original copies and not the virtualized ones (CMIIW). Also I assume that you setup processed was executed elevated
The idea is to create a "general" process (non-elevated, legacy), that your main installer should run. This process will create a file name in the user chosen folder with a name and contents that both your programs know (for example, test73819704.bin). If the folder virtualized, this file should appear in the user VirtualStore and SHOULD NOT in the original one (from the point of view and privileges of the installer).
So for chosen C:\Program_Files_But_Not_Necessarily and Process-1 (elevated)
Process-1 ensures there's no file C:\Program_Files_But_Not_Necessarily\test73819704.bin
It launches Process-2 with no elevation
Process-2 creates C:\Program_Files_But_Not_Necessarily\test73819704.bin and checks whether it really exists. If exists it would return with a good return code, otherwise with a "failed" one.
Process-1 waits for Process-2 and analize the result. If good, checks for C:\Program_Files_But_Not_Necessarily\test73819704.bin, if it exists, go for "Bingo! No virtualization occured", if doesn't exist, "Bad, let's find some other storage place". If the code from the Process-2 is "failed" one, show the user some error message.
Unfortunately I could not test it right now, but I guess it should work and there's a logic behind this, with Process-2 you just emulate the behavior of your main program )
We allow our users to install anywhere...
If the user has taken the default, and is installed in Program Files, we make the assumption that we need to write to Documents and Settings/Users. Otherwise, we write our data to a folder under the directory the software is in. This of course can still cause problems, and the install does indeed allow people to choose a different data location if they choose to not go for the default.
On top of that, it's a simple ini file change and a copy to move the data.
On start up we detect if we are in the Program Files directory by comparing the value we obtain from SHGetFolderPath(CSIDL_PROGRAM_FILES) with the start of the path the executable is in.
What is the recommended location to save user preference files? Is there a recommended method for dealing with user preferences?
Currently I use the path returned from typeof(MyLibrary).Assembly.Location as a default location to store files generated or required by the application.
EDIT:
I found two related/interesting questions:
Best place to save user information for Windows XP and Vista applications
What's the way to implement Save / Load functionality?
EDIT #2:
This is just a note for people like me who had never used settings before.
Settings are pretty useful, but I had to do a whole bunch of digging to figure out what was going on (coming from the Python world, not something I am used too). Things got complicated as I wanted to save dictionaries and apparently they can't be serialized. Settings also seem to get stored in 3 different files depending on what you do. There is an app.config, user.config and a settings.setting file. So here are two more links that I found useful:
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/ddeaca86-a093-4997-82c9-01bc0c630138
http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/efe370dc-f933-4e55-adf7-3cd8063949b0/
You can use the Application Settings easily enough.
If you haven't done so before just right click on the project and choose Properties. Select the Settings tab. Make sure you chose "User" for the scope (otherwise the setting is read-only).
The code to access this is simple:
forms.Width = Application1.Properties.Settings.Default.Width;
If you need to save it:
Application1.Properties.Settings.Default.Width = forms.Width;
Application1.Properties.Settings.Default.Save();
In the sample above, Width is the custom setting name you define in the Settings tab and Application1 is the Namespace of your application.
Edit: Responding to further questions
You mentioned you wanted to store Dictionary objects in the Settings. As you discovered, you can't do this directly because Dictionary objects are not serializable. However, you can create your own serializable dictionary pretty easily. Paul Welzer had an excellent example on his blog.
You have a couple of links which sort of muddy the situation a little. Your original question is where to save "User Preference Files". I'm pretty certain Microsoft's intention with the Settings functionality is exactly that... storing user skin preferences, layout choices, etc. It not meant as a generic repository for an application's data although it could be easily abused that way.
The data is stored in separate places for a good reason. Some of the settings are Application settings and are read-only. These are settings which the app needs to function but is not specific to a user (for example, URIs to app resources or maybe a tax rate). These are stored in the app.config.
User settings are stored in an obfuscated directory deep within the User Document/Settings folder. The defaults are stored in app.config (I think, can't recall for certain off the top of my head) but any user changes are stored in their personal folder. This is meant for data that changes from user to user. (By "user" I mean Windows user, not your app's user.)
Hope this clarified this somewhat for you. The system is actually pretty simple. It might seem a little foreign at first but after a few days of using it you'll never have to think of it again... it just works.
When running as non-admin or on Vista you can't write to the "Program files" folder (or any sub folder of it).
The correct location to store user preference is (replace MyCompanyName and MyApplicationName with the correct names, obviously)
On disk:
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\MyCompanyName\\MyApplicationName"
Or in the registry under the key:
HKEY_CURRENT_USER\Software\MyCompanyName\MyApplicationName
Those location are per-user and they work with non-admin user, several users using the same computer, fast user switching, terminal services and all the other ways people can interact with your software.
If you need a common location for all users then:
It will only work when the user run as an administrator
It will not work reliably on Vista
You have to take care of everything yourself (like two users running the application on the same computer at the same time via fast user switching).
and the locations are:
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationCommonData) + "\\MyCompanyName\\MyApplicationName"
Or in the registry under the key:
HKEY_LOCAL_MACHINE\Software\MyCompanyName\MyApplicationName
You can use isolated storage. You can isolate by user, assembly and/or domain.
Introduction to Isolated Storage
http://msdn.microsoft.com/en-us/library/3ak841sy(VS.80).aspx
Types of Isolation
http://msdn.microsoft.com/en-us/library/eh5d60e1(VS.80).aspx
the following seems to be the best option:
Application.UserAppDataPath