- The Secondary Logon Service
- But I Hate the Command Prompt!
- Network Credentials
- A Sample Setup for a VS.NET Developer
- Debugging
- Creating Web Projects in VS.NET
- Writing Code That Can Be Used by a Non-Admin
- Isolated Storage
- Installation Tips
Writing Code That Can Be Used by a Non-Admin
One result of developing code as a nonprivileged user is that you'll be more likely to produce programs that run without requiring elevated privileges. So this item would not be complete without pointing out the most common reasons that programs break for nonprivileged users, and helping you do better.
If there were only one bit of advice I could give on this topic, it would be this: Separate program files (executables, DLLs, etc.) from data files! Normal users don't have write permission under the Program Files section of the file system, [4] which means that your program won't be able to write here either, so don't try (this is an example where running as a normal user can help you catch silly mistakes early). This is by far the most common bug that causes programs to require elevated privileges in order to run.
As part of the Windows Logo program, Microsoft provides guidelines on where to store data files. The .NET Framework has methods that allow your program to discover the appropriate location for data files at runtime, so there's really no excuse for the plethora of apps that insist on writing data to their install directories. Figure 9.3 shows the various types of data, the recommended locations, and the enumerations in the .NET Framework used to look up these locations at runtime, because the actual paths I provide here may be different on each machine. Here's a link to the Logo requirements.
Figure 9.3 Recommended data file locations
I strongly recommend reading the section on data and settings management, as it provides further tips on using these common directories.
Note that I'm not recommending writing directly into any of these directories. Rather, you should create a subdirectory that's unique to your application and store your data files under it. The Logo requirements specify the directory structure as follows: [company name]\[product name]\[version]. Here's some C# code that prints out the recommended directory for the second item in Figure 9.3.
using System; class App { static void Main() { string path = Environment.GetFolderPath( Environment.SpecialFolder.CommonApplicationData ); Console.WriteLine(path); } }
If you're building a Windows Forms application, your life is even easier, because the Logo requirements for forming your product's subfolders are implemented for you via the following properties on the Application class.
-
UserAppDataPath
-
LocalUserAppDataPath
-
CommonAppDataPath
Here's a program that prints out these paths. Compile and run it; then go look at your user profile directory (Item 19)! The subfolders for your product are created automatically. The first time you read one of these properties, the Application class creates the folder on your behalf (if it doesn't already exist), using the metadata provided by the three assembly-level attributes shown in the following code sample:
using System; using System.Windows.Forms; using System.Reflection; [assembly: AssemblyCompany("ACME")] [assembly: AssemblyProduct("WidgetManager")] [assembly: AssemblyVersion("1.1.0.0")] class App { static void Main() { // simply accessing these properties creates // subfolders based on company/product name // and version, according to logo requirements! Console.WriteLine("Roaming Settings Folder: {0}", Application.UserAppDataPath); Console.WriteLine("Local Settings Folder: {0}", Application.LocalUserAppDataPath); Console.WriteLine("Shared Settings Folder: {0}", Application.CommonAppDataPath); } }