Application Migration - Vista/Win7 Compatibility

Posted by Hugh Ang at 12/16/2009 01:07:00 AM

It has been a while since the last time I blogged. The theme of my work for the last 4 months or so is really migration, migration, and migration!

  • First I helped our team with a VB6 to VB.NET migration project that ran into some sticky interop problems.

  • Secondly I worked as an advisor for a customer who was in the process of migrating their apps from Win2K to Vista. Please don't ask me why they chose to go to Vista while Win7 was coming out - it was a decision already rationalized by the management when I was brought in.

  • And lastly, just a couple of weeks ago, I helped Microsoft deliver a Win7 training course for a customer who is looking to migrate to Win7 in the next 6 months. Although it is not unusual that I present in a conference room or mentor developers privately, this was actually my first time to do a formal training. The sessions were recorded and are being made available for later reuse by the customer. Speaking of the sessions on tape, I actually saw Oliver Stone and Michael Douglas when they were shooting Wall Street 2 on site at the Borders book store at the corner of Wall Street and Broadway. And that was when I was working on the Vista migration mentioned above.

Enough with the chronology and my celebrity sightings. As the title suggests, I'd like to cover the most common compatibility issues for Vista/Win7from a developer perspective. So here are the two top issues I have seen so far:

  • Writing to %ProgramFiles% (e.g. C:\Program Files) and %SystemRoot% (e.g. C:\Windows) locations

  • Writing to registry hive: HKLM\Software

It is quite common that legacy apps write configuration data to the above locations. But with UAC enabled in Vista/Win7, an admin user will be running an app with standard user privileges unless the app has a manifest explicitly requesting admin privilege or the app is started with "Run as administrator" context menu; And since standard user will only have read/execute rights to those locations, the attempt made by those apps to write configuration data to those locations will fail. Using the icacls at the command prompt shows the ACL of %ProgramFiles% as in the following on my machine:

C:\Program Files>icacls .
. NT SERVICE\TrustedInstaller:(F)
NT SERVICE\TrustedInstaller:(CI)(IO)(F)

There is an additional twist here. The app may not be failing but you will not see files or registry keys written to the intended location. This is the work of data redirection(or UAC virtualization). The details can be found here. But basically:

  • Writing to %ProgramFiles%\MyApp\myapp.ini gets redirected to C:\Users\Username\AppData\Local\VirtualStore\Program Files\MyApp\myapp.ini

  • Writing to HKLM\Software\MyApp\ gets redirected to HKCU\Software\Classes\VirtualStore\MACHINE\Software\MyApp

When virtualization happens, you can fire up Process Monitor and notice a REPARSE event, followed by writing to those redirected locations.

As the redirection is on per-user basis, this can mess up the intended behavior of the application. For example, the application may be intended to be used by multiple users on one machine and the configuration data should be shared. Microsoft is making no guarantee that the virtualization will be in future Windows. So what to do as a developer? The best practice for writing per machine configuration data is using %ProgramData% (e.g. C:\ProgramData). For per user configuration data, use %LocalAppData% (e.g. C:\Users\User\AppData\Local) for local or %AppData% for roaming user profile.

Running icacls on %ProgramData% shows that a standard user would have additional AD(append data/add subdirectory), WD(write data/add file), WEA(write extended attributes) and WA(write attributes) privileges:

C:\ProgramData>icacls .

And lastly, don't hard code any of the paths we have talked about. There are well-known APIs to get them. In .NET, follow this sample:

string path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);


path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);


path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);

And if you write C++ code, here is a sample:

void ShowFolders(HWND hWnd)


    LPWSTR wszPath = NULL;

    HRESULT hr = SHGetKnownFolderPath(FOLDERID_ProgramData, KF_FLAG_NO_ALIAS | KF_FLAG_DONT_VERIFY, NULL, &wszPath);

    if ( SUCCEEDED(hr) )


        // work with wszPath





    hr = SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_NO_ALIAS | KF_FLAG_DONT_VERIFY, NULL, &wszPath);

    if ( SUCCEEDED(hr) )


        // work with wszPath       





    hr = SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_NO_ALIAS | KF_FLAG_DONT_VERIFY, NULL, &wszPath);

    if ( SUCCEEDED(hr) )


        // work with wszPath   





Hotfix KB971030 Released

Posted by Hugh Ang at 9/02/2009 04:58:00 PM

You can finally download this hotfix from here and the detailed information is available here. According to the information posted there, it is a fix for an access violation problem when making virtual function calls to the IList<T>, IEnumerable<T>, or ICollection<T> interface. I am not sure yet if this is another manifestation of the same dispatch token problem I described in my previous blog or the CLR team simply bundled together several virtual dispatch bug fixes that just include what I found.

I ran the same test harness that I used before and confirmed that the hotfix does indeed resolve the problem.

I was having some trouble installing the hotfix today but eventually got it installed. It turned out that my OS was Vista SP1 and I had to upgrade it to SP2 in order to install the hotfix. If you have another OS and wondering about the same question as Chris Dion had, the hotfix should be applicable to Windows Server 2000, Windows Server 2003, Windows Server 2008 and Windows XP.

CLR Virtual Call Stub Issue Resolved

Posted by Hugh Ang at 5/15/2009 01:51:00 PM

Good news - I have just received words from the Microsoft CLR team that the issue I detailed in this blog has been fixed in an upcoming QFE, which will be available for download through the Support/KB site using KB971030 in about a week. This also means that the fix will be automatically included in any future 3.5 service pack release. In addition, this has been fixed in the upcoming 4.0 release. I will try the fix in a week and keep everyone posted.

Making Assumptions in Application Design

Posted by Hugh Ang at 2/18/2009 11:46:00 AM

Back during the holidays, I wrote a small .NET program to manipulate my Canon XTi camera, which was connected to the PC via USB. Everything worked great when I was using my laptop that had Vista on it. But on my wife's laptop that had XP, the performance became unbearable. My utility program would wait for several minutes before I could start using it. The program's thread was pretty much idle during the waiting so I was asking myself: could this be the PC hardware? I tested this program on one of my desktops that also had XP. Nope, still the same poor performance. I then updated the camera's firmware and that didn't resolve the issue either. I began to suspect that this was OS related. Sure enough, when I plugged in the camera without my program running, XP took a much longer time than Vista to come up with the camera and scanners wizard. I noticed that while XP seemed to be cluelessly waiting, the CF card indicator light of the camera was flashing madly. I realized that XP was probably trying to download pictures from the camera, which was busy reading from the CF card. At the time, I had about 300 high resolution pictures on the 2GB CF card. After I switched it with an empty CF card, the performance problem just went away.

The morale of the story is that we need to be extra careful when making assumptions for users when designing UI applications. In this case, XP made a not necessarily wise assumption about the intention of plugging a camera into the USB port. Even for users who do want to download pictures this way, there is no visual clue provided, leaving users wonder what is going on.