Posts in Category "Windows"

AIR 2, NativeProcess, and 64-bit Windows

AIR 2 includes, among other new APIs, the ability to launch and communicate with sub-processes via the NativeProcess API. The API can launch executables bundled with your application or installed separately. On Windows, it turns out that the latter can be trickier than expected when running on a 64-bit system.

64-bit versions of Windows can run both 32-bit and 64-bit processes. This makes it possible for users to transition to 64-bit over time, keeping their 32-bit applications with them until 64-bit versions are available. This is why AIR applications, which for now remain 32-bit applications, can run on 64-bit versions of Windows. Most of the time, this works seamlessly.

In order to ease porting 32-bit applications to 64-bit Windows, 64-bit applications continue to use the %windir%\system32 directory for 64-bit libraries. This is great for 64-bit applications, which continue to work, even with explicit references to this directory. However, it would break all 32-bit applications, as they can’t load the 64-bit libraries.

To work around this, Windows automatically redirects most accesses to this directory from 32-bit applications running on 64-bit Windows to a different location: %windir%\SysWOW64. (WOW64, despite its name, is the subsystem that runs 32-bit applications on 64-bit Windows.) Again, most of the time this works seamlessly.

This approach will if you’re trying to launch an executable from %windir%\system32 if there is no 32-bit version of the same executable in %windir%\SysWOW64. In this situation, you can see in Explorer that the executable exists in %windir%\system32, but when you check the same location via your 32-bit application, the file, due to redirection, will not be present. If this happens to you when using the AIR NativeProcess API, you’ll get an error (3214) that the executable you’re trying to use is invalid.

The workaround to the workaround? Starting with Windows Vista, you can force direct access to the 64-bit directory by using %windir%\sysnative. It’s not a real directory, but it is recognized by the redirection logic and pointed to the real %windir%\system32 directory. For Windows XP, you’ll have to resort to system calls to turn off redirection. For a complete description, see the MSDN File System Redirector documentation.

Upgrade Codes, Product Codes, and Silent AIR Application Uninstall

Those who sign up for the Adobe AIR redistribution license have had the ability to silently install and uninstall AIR applications since the AIR 1.0 release. Unfortunately, the silent uninstall support on Windows is a bit rough. I’ve included below a link to a utility I wrote that eases the problem a bit. But first, a little background on the issue.

When an AIR application is installed on Windows, it’s installed via Windows Installer. This is a good thing; it allows leveraging all the capabilities of Windows Installer. For example, silently uninstalling an AIR application on Windows can be accomplished directly via the “msiexec” utility that is part of Windows. All you need to provide to msiexec is the product code of the application.

AIR applications don’t inherently contain product codes—they’re specific to Windows Installer—and you won’t, for example, find one in your application descriptor. Furthermore, Windows Installer requires that product codes change—even for the same application—under certain circumstances. In order to play it safe, AIR generates a unique product code for each version of your application. This, in turn, means you need to know the product code associated with the specific installed version of the application in order to uninstall it. This is a hassle.

Fortunately, Windows Installer also associates an upgrade code with each application. An upgrade code is basically an application identifier that never changes and, given an upgrade code, you can look up the corresponding product code. The mapping from upgrade code to product code is stored in the registry at application install time. Like product codes, AIR generates an upgrade code for your application. Unlike product codes, upgrade codes are the same across all versions of your application and are easily determined via the OSID application that comes with the redistribution support.

Unfortunately, the only way to look up that mapping is via the MsiEnumRelatedProducts() system call, and the msiexec utility won’t do it for you. (Theoretically you can look this mapping up yourself in the registry, but that turns out to be fairly complicated, and I’m not sure it can be done reliably.)

How much of a problem this is depends on the uninstall technology you’re using, whether or not it can perform this lookup for you, and whether or not you’re in a position to write a few lines of C code to perform the lookup. For anyone out of luck on all counts—or just curious—I’ve written a small utility called “msiu2p”. You can download msiu2p here. (The zip package includes the executable and the source.)

Here’s an example:

c:\ msiu2p {8DA920D5-C41C-42E0-BF31-87BA49984EE4}
{A2BCA9F1-566C-4805-97D1-7FDC93386723}
c:\

Of course this isn’t useful just for AIR applications, either: It’s a handy complement to msiexec for any application using Windows Installer.

We plan to improve AIR’s intrinsic support for this kind of thing in an upcoming release. In the meantime, I hope this utility will help fill the gap for those who need it.

Tools: Procmon

Back to developer tools.

In the platform-specific category, Procmon is my favorite on Windows. It captures registry, file system, and process events for any process. You can use it to debug your own programs and just about anyone else’s, too. It’s originally from Sysinternals, now provided by Microsoft directly.

For example, I once used it to debug some custom build steps in Visual Studio that weren’t behaving. Using Procmon, I was able to determine which files Visual Studio was checking timestamps on. It turned out an incorrectly entered output list was causing Visual Studio to look for files that didn’t exist and causing the step to run every time. Sure, maybe I’d have seen that if I stared at the output list long enough. But it was easy to spot in Procmon.

A few features I’ve found most useful:

Filtering by process name. You can filter events in about a zillion ways, but the most useful is to exclude based on process name. Find an event from a process you don’t care about, right-click, and select Exclude. Procmon remembers these settings between invocations, so it’s easy to reduce clutter by excluding Explorer.exe, etc.

Filtering by event type. In the toolbar you’ll find three buttons to show/hide file events, registry events, and process events. Again, eliminates a lot of clutter if you know which type of event you’re looking for.

Saving log files. You can save your captured event logs. I encourage our QE team to use this feature and attach the log files to bug reports. I can open the logs back up in Procmon and get a good idea of what happened.

You’ll also be surprised at all the stuff that Procmon captures going on under the covers. For example, you can see all of the work your application does before it starts executing your code. Sometimes I’m amazed applications ever finish starting!

Partial Explanation of MSI Feature Selection

I really do want to write some entries about handling async APIs as I recently promised, but I’ve been engaged in hand-to-hand combat with some installer issues recently, so for now–a post about installers.

Installation of both Adobe AIR itself and AIR applications is done via Windows Installer–more commonly referred to as MSI. Using MSI is the doing the "right thing", but it certainly isn’t the easy thing.

One of the most frustrating aspects of MSI is that its internal model is opaque. I can only assume it’s terribly complicated; it certainly isn’t documented. And while usually the inner workings of a technology can be gleaned not only from documentation but also its API, the MSI API is itself rather convoluted. Whether that’s because the underlying model is convoluted or just obscuring that model I just don’t know.

(By the way, for a great discussion of internal models of operation and how they’re surfaced in everyday things like refrigerators, check out Don Norman’s classic, "The Design of Everyday Things".)

With that introduction, here’s my best attempt at a partial explanation of how features are selected for installation or removal during an MSI install operation. At the very least this will serve to document what I just spent several hours figuring out.

Every feature has a level assigned to it, the level being a non-negative number. Unless you override the defaults, MSI will install every feature with a level of one. A feature with level zero is never installed, and in fact setting a feature level to zero can be a dangerous thing to do–but that’s a topic for another post. Features with higher numbers can be installed by changing the INSTALLLEVEL property, but that’s not what this post is about either so no more on that topic.

You can also change the set of installed features using a set of properties. There are many of these, but for my purposes I’ll stick with just ADDLOCAL, REMOVE, and REINSTALL. Once you set one or more of these properties the level-based behavior above no longer applies. Instead, very feature listed in ADDLOCAL is installed, and every feature in REMOVE is–well, removed. Features in REINSTALL are essentially patched–if they’re installed.

Now, you might be wondering about REINSTALL, since it sounded like we were talking about install scenarios–not patches. But–and here’s one of those strange parts of the MSI model–in MSI, any "installation" can add, remove, or patch features. In other words, what you might naively call installs, patches, and uninstalls.

(To make things even weirder, other parts of MSI are inconsistent about this. For example, the "msiexec" command line tool does, as the model would predict, allow you to uninstall a product using the /i (install) option. But it also has a /x (uninstall) option. The latter would seem to suggest that the model included a notion of uninstalling, but I’m pretty sure it doesn’t. The API, for example, doesn’t have an uninstall function–products are typically uninstalled by calling MsiConfigureProduct. Go figure.)

Let me illustrate with a simple scenario. Suppose I have a product P with three features, F1, F2, and F3:

To install both features I can either (a) not set any properties, because they’ll be installed by default or (b) set ADDLOCAL=F1,F2,F3.

If I want to install just F1 and not F2 or F3: ADDLOCAL=F1.

Finally, suppose F1 and F2 are installed (but not F3) and I wish to patch F1, install F3, but uninstall F2: ADDLOCAL=F3 REMOVE=F2 REINSTALL=F1.

So there you have the essence of the model; an install operation is really a set of install, uninstall, and patch operations. Of course there’s more to it than that, as there are different ways to install features, etc. And that’s why this entry is titled a "partial explanation."

A note in closing: The log files generated by msiexec are your friend for debugging MSI issues; use /lv*x to get the most information. If you’re debugging issues related to feature selection like I describe here, look for entries with this form:

Feature: Runtime; Installed: Local; Request: Reinstall; Action: Reinstall

They’ll give you a good idea of which operations MSI thinks you’ve requested, including the state of the feature before the operations begin.

 

Don’t Rename that MSI

The installer for the Apollo alpha release was made available, for Windows, as an MSI file. MSI files are the native format of the Windows Installer service. They’re essentially a single-file database containing the data required to install (and uninstall) an application.

It turns out that offering your installer download as an MSI file isn’t a terribly good idea. Unfortunately, we didn’t discover this until it was too late for the alpha release.

The first half of the problem arises because Windows Installer remembers the name of an MSI file when an application is installed, and it requires that subsequent installations of the same product use the same file name. (Windows Installer considers two products to be the “same” if the MSI file for both contain the same product GUID.)

The second half of the problem is your browser, which likely has a habit of renaming files that you download. For example, if you download the same file twice, it might helpfully append “(2)” to your second download to avoid overwriting the first.

Taken together, these two behaviors can make it surprisingly likely that you try to install the same product twice from MSI files with different names. If you trace the behavior of Windows Installer when attempting to open the second MSI file, you’ll find that it starts by correctly opening the second file, regardless of its name. Later, however, it will try to re-open that file using the original name.

This behavior doesn’t seem to be well documented, although I have found a reference in this Windows Installer Team Blog entry–look for Rule #14. I’m hard-pressed to argue that it’s not a bug, but maybe there’s a good reason for it that I just haven’t thought of yet.

Unfortunately, all of this can make Apollo’s installation experience look lousy. For example, see this blog about installing Apollo.

We’ve addressed all of this in the upcoming beta release by making the installer download for Windows an executable. It still contains an embedded MSI file and uses Windows Installer, but no one–not you, and not your browser–has the chance to give that MSI file the wrong name. Plus, it’s now got a nifty UI!

Window- and Console-Friendly Win32 Applications

[This entry was updated on May 2, 2007 with additional information about limitations of this technique when used with the DOS shell, as noted in the comments. –Oliver]

It’s sometimes handy to create an application that can run either with a GUI or, if started from the command line, a command line UI. For example, you might want an installer to work this way so that it can support both GUI-driven and “silent” (command-line) installations. Windows provides a simple but not necessarily obvious way to create these dual-mode applications.

Most Windows applications run on the windows subsystem. These applications can try to write to the console, but they aren’t attached to one by default. Using this method your GUI will work just fine but any command line output will be discarded.

An application can be run on a different subsystem, of which “console” is one choice, by setting the /subsystem flag of the linker. When these applications are run they are attached to the console, and they can also open new windows. The catch is that Windows will make sure there is always a console present. If the program is run by, say, double-clicking it in Explorer then Windows will first create a new black-and-white console window, attach the application to it, and then launch the application. The application can close the console window, but not before it’s been seen by the user.

Here’s an approach that does work: Create a windows subsystem application and call AttachConsole(). If run from the Explorer there’s no console to attach to, but that’s ok–you weren’t going to use it, anyway. If your application is run from the command line then this call will attach your application to that same console–which is exactly what you want.

This technique works when running the application from bash and similar shells, from Ant scripts, and so on. However, it does not work with the DOS shell because the DOS shell will not wait for any GUI (Windows subsytem) application. You can work around this in the DOS shell using the /wait option to the start command, like so:

c:> start /wait dualmode.exe