Archive

Archive for January, 2007

Windows Special Folders

January 23, 2007 1 comment

We were watching a Microsoft Web Seminar yesterday on Windows Vista User Account Controls, and one of the code samples referenced the users LocalApp directory. This led to a discussion of where to store things like binary files, config files, and .ini files. In the past, you may have stored this in the Program Files directory. This is not a good practice, because there is no guarantee that this is where the user installed the software. Fortunately, in .NET, you can get the installed directory from an Assembly object, but this is still not a good practice
because if the software is uninstalled and reinstalled, you could lose those files, frustrating your users.

To compound this problem, in Vista the Program Files directory requires Administrator priveleges. The whole point of UAC, of course, is to limit potentially dangerous code from executing and to allow users to truly operate in a “Standard User” account environment. Even a user with Administrator priveleges executes programs with Standard User access [NOTE: this behaviour can be overridden by manually assigning a manifest to the assembly instructing it to run as Administrator]. This means that in order to access a config or binary file stored in Program Files requires the user to bump up their security by responding to a Dialog Box. One of the Vista goals that Microsoft has set forth for ISVs is that our software should run as Standard User. That and the user being constantly prompted to upgrade their security level are reasons enough not to rely on Program Files for storage in Vista.

Another typical solution is to simply create your own directory structure in C:\, but I find that unrealiable as well. Some users like to “clean up” their C:\ drive on occassion, and your application may all of a sudden not work anymore. Plus, it makes curious users into dangerous users if they can directly access config files or who knows what: I meant, these are users we’re talking about, and you just never know what they might do.

So the question becomes “Is there a safe, reliable directory we can use to store and retrieve such files from?” The answer is yes! .NET provides access to a series of special folders, enumerated in Environment.SpecialFolder. (The Environment namespace is part of System, so does not need to be referenced, it is always just accessible) Following the link will show you the list of Special Folders, most of which are pretty straight forward, like My Computer, My Documents, etc. There is one in particular, though, that is not so straight forward, but is exactly what we need: LocalApplicationData. This is a directory buried within the User structure. On my XP box, the path looks like this: C:\Documents and Settings\Joel\Local Settings\Application Data. Underneath this directory are a listing of other directories, usually company names (Microsoft has one, as does Google), and inside those directories are directories for specific Applications.

This is where we want to store our persistant data. It is safe from being overwritten, does not require Administrator priveleges, and most curious users aren’t going to go tampering with it. Another good thing about this approach is that we are going to use a system name to get the path: we are not going to hard code this path structure! I don’t have a Vista machine yet, but there is no guarantee that Microsoft kept the same structure. What they will keep, however, is .NET’s ability to find the path of this folder on any given system.

To get the path, you need to pass the SpecialFolder enumeration value you want to the Environment.GetFolderPath method:

// Get Special Folder path
string myLocalAppPath = Environment.GetFolderPath( Environment.SpecialFolder.LocalApplicationData );

Your application directory will not be automatically created beneath this path. You will need to check for the existence of it and create it if necessary. This would be an ideal task for a Custom Action in the Installer.

This should provide the ideal location for your application settings and persistent configuration files.

Categories: .NET, Vista

Deploying CF .NET 2.0 applications using MSI

January 17, 2007 Comments off

So I’ve been developing Smart Device apps for the last two years, both in VS2003 and now in VS2005. But as the only CF developer in a tiny shop, I have always been able to install them by just using the Deployment option in Visual Studio. Now, however, one of the products I’ve been working on is ready to go to the field for some testing, which means other people have to be able to install it.

Frankly, most of the documentation on deplying CF.NET apps is pretty scary. CAB files, custom INI files, Registry entries, the works. I’ve definitely been spoiled by the MSI features available to Windows forms apps. So I’ve been digging around and experimenting, and I created a CAB file for install and then found the Smart Device CAB project, so I created that but it still required the user to manually copy it over to the device and double click it and yada yada yada. Too much for most of my target audience, and not very professional.

So I dug some more, and I was about to give up, when I found this article on MSDN about using MSI to handle the install to a Smart Device. I went through the article, and after a little trial an error I got it to work. Here are the highlights:

  1. Create your solution and build all the projects. Use Release to keep them as small as possible.
  2. Add a Smart Device CAB project to your solution. Add all your project outputs to the applications folder and add a shortcut to your EXE to the Program Files folder. Build this project.
  3. Add a new Class Library project to your solution. This is an MSI installer helper class that handles events like before_install and after_install. The cool thing is that these events will be found and used automagically later. Fill out the events and build this project. This file has some Registry stuff in it and references a custom INI file that you will need to create, but the forumla is very simple.
  4. Add a new Setup project to your solution. This will be the MSI file that is eventually used to communicate with ActiveSync and install the CF application. By adding custom actions to the installer and referencing the helper DLL we created in step 3, the before and after events will automagically find themselves and fire.

OK, so this is in no way a step by step instruction list. For that, you will want to read the article (like 20 times). It is a little dense but thorough, and I was able to get it to work. I did encounter a permissions problem in the afterInstall event, so I still need to hash that one out, but it did install the app on my device.

One quirk I found was that the article instructs you to add a reference in the MSI project to the System folder and to place your output there for the CABs and the INI file. Unfortunately, this doesn’t jive with the pathing samples in the Helper class code in the article, which references System/TEMP/MyProject. In looking at it, I think the TEMP path is the best way to go, so just create the TEMP/MyProject path in the System special folder and dump your output CAB and INI files there.

Next I’ll be tackling how to integrate CF .NET deployment in the same MSI, so stay tuned.

Windows Vista IS the Killer Feature

January 16, 2007 1 comment

SearchWinIT.com has an article outlining the new must-have features for Windows Vista. The author, Bernie Klinder, notes that there isn’t a single killer feature, but rather Vista is ful of smaller features that overall add up to the “must-have” aspect of Vista. He says once you’ve used Vista, it is almost painful to go back to XP. Here is his list of items:

  • Integrated Search
  • Power Management
  • Network Management
  • Ad Hoc Wireless
  • Presentation Mode (AWESOME)
  • Previous Versions
  • Mobility Center
  • Document Previews
  • Guided Help and Automated Diagnostics
  • Aero

Not all of these features will appeal to everyone, but overall Vista looks very promising. I plan on getting a new laptop once the OEM version comes out… I’ll be sure to review it in detail then. In the meantime, read the rest of Kindler’s article for more details.

Categories: Vista

C# foreach howto.

January 16, 2007 2 comments

I was getting sick of doing for loops so I decided to read up on the foreach statement. The foreach statement is small, clean, quick and much easier to read if you ever plan on having a programmer help you out with your coding. There is no need for me to ramble on so check out this code. The foreach statement basically lets you define an object, and loop through a collection of the same object type.

This simple example “checks” all the check boxes for all the items in a ListViewControl.

foreach (ListViewItem lvi in lvTBS.Items)
{
    lvi.Checked = true;
}

This is way better than doing this:

for ( i=0; i<=ListViewControl.Items.Count(); i++ )
{
    ListViewItem lvi = ListViewControl.Items[i];
    lvi.Checked = true;
}
Categories: .NET, C# 2.0

Finding an Enum value based on its text

January 4, 2007 1 comment

I’ve been a fan of custom Enums since I started coding for .Net: like most software packages, we have tons of selection lists. Many of these are table driven, code-based lists like so:

Code : Description
10 : Asparagus
12 : Carrot
73 : Tomato

etc, etc.

Naturally, I don’t want my users to have to know that 73 means Tomato, so like a good little developer, I put these values into an Enum:

public enum Vegetables
{
    Asparagus = 10,
    Carrot = 12,
    Tomato = 73
}

Then I use that Enum to populate a ComboBox on my Form. To do so, I utilize the Enum class's GetNames method.

foreach (string s in Enum.GetNames(typeof(MyClass.Vegetables)))
{
    this.cboxVegetableNames.Items.Add(s);
}

The trick here is to point the typeof parameter to the full class designation of the enumeration you want to list. This method returns an IEnumerable you can use to loop through the names.

So far so good: pretty straight forward and probably something most of us have already figured out. The problem I had recently was that I needed the Enum value in order to properly update a database. In other words, when the user selected Tomato, I needed 73. Getting the int value of an enum is easy enough via a simple cast:

MyClass.Vegetables veggie = MyClass.Vegetables.Tomato;
int veggieValue = (int)veggie;

So if I could figure out which Enum value was selected, I could easily get the int. The problem was, I only had the Text string from the ComboBox to go off of. I suppose I could do some sort of brute force loop through all the Enum members until I found a matching string, but that seems like overkill. It would be especially bad if I had lots of options in the ComboBox and lots of ComboBoxes.

Fortunately, I was able to find something a little better built right in to the Enum class:

MyClass.Vegetables veggie = (MyClass.Vegetables)Enum.Parse(typeof(MyClass.Vegetables), this.cboxVegetableNames.SelectedItem.ToString());
int veggieValue = (int)veggie;

It's definitely a little ugly, but gets the job done. The trick to getting this to work is the cast into an Enum variable of the same type. Again we use typeof() to get a reference to the full class name of the Enum and then cast the results into an int.

Now you can easily work with Enums to put the list of strings into a ComboBox and later retireve the Enum value from the selected string. In a future article, I'll demonstrate how you can use attributes to show different text than the actual member name.

Categories: .NET, .NET 2.0, C# 2.0
Follow

Get every new post delivered to your Inbox.