So, while evaluating AIR as a potential wrapper for our latest project, our only major issue is that AIR doesn't give you the option of creating more than one icon in the Windows Start Menu. Our products tend to come with associated config applications or support documents, and historically we've always put links to them in the Start Menu.
So I started to look into how to create Windows shortcuts using AIR.
This should have been easy, but thanks to Microsoft's proprietary binary file format, it really wasn't.
The standard Windows shortcut file is a .lnk file. You can read about it here.
As you'd expect, it being a Microsoft format, there's no official documentation on the file format itself. Microsoft expect you to use their COM objects and APIs to both read and write these files. Unfortunately we've got no way to get at these APIs from AIR.
However, some people - notably Jesse Hager - have reverse-engineered the binary format, at least well enough to read shortcut information from a .lnk file.
But having spent a day creating an AIR class that would write .lnk files according to Jesse's spec, I discovered that the minor errors and handful of unknown byte strings in Jesse's document really, really mattered. Despite doing a number of tests (comparing AIR-generated files to Windows-generated files, fixing byte alignment, adding Unicode support) nothing I did resulted in a working shortcut, at least on Vista. Eventually I was forced to throw in the towel, as it was proving more effort than reward.
However, there is an alternative.
Windows also supports .url files; these are intended to be Internet Explorer links, but it turns out that you can use them in an identical way to normal Windows shortcuts. Happily, they are simple text files and format is really easy.
The only thing they don't support which .lnk files do is the ability to specify command-line arguments to the application you are launching. But you can get around that with a bit of creative thinking and use of Windows .bat files.
Anyway - here's a very quickly thrown-together class to allow the writing of .url files from AIR:
package com.awen.air { import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; /** The Windows native shortcut (.lnk) file structure is a binary mess; a real * pain to encode and decode without using Win32 system functions (I know, * I've tried). * However, an alternative exists - the Windows .url format. * * It does most of what a shortcut does bar one thing - no command-line * arguments, I'm afraid. Our solution is to link to a batch file * in such circumstances... * * (c) 2008 Awen. Feel free to use this in your own apps. * * Usage: * var fileShortcut:WindowsURLShortcut=new WindowsURLShortcut("file:///C:/Windows/notepad.exe"); * fileShortcut.workingDirectory="C:\\Windows\\"; * fileShortcut.write(File.userDirectory.resolvePath("Desktop/Notepad.url")); * * var netShortcut:WindowsURLShortcut=new WindowsURLShortcut("http://www.google.com"); * netShortcut.write(File.userDirectory.resolvePath("Desktop/Google.url")); */ public class WindowsURLShortcut { /** URL passed in to the constructor. */ public var url:String; /** Optional working directory */ public var workingDirectory:String; public static const SW_HIDE:int=0x0; public static const SW_NORMAL:int=0x1; public static const SW_SHOWMINIMIZED:int=0x2; public static const SW_SHOWMAXIMIZED:int=0x3; /** ShowWindow value */ public var showCommand:uint=SW_NORMAL; /** IconIndex */ public var iconIndex:uint=0; /** Optional IconFile */ public var iconFile:String; public static const HOTKEY_SHIFT:uint=0x0100; public static const HOTKEY_CTRL:uint=0x0200; public static const HOTKEY_ALT:uint=0x0400; /** For a hotkey, set this to the ASCII value of the lowercase * key e.g. for 'a' set this to 65. Or it with HOTKEY_xxx for key * modifiers e.g. for CTRL+SHIFT+a, use * hotkey=HOTKEY_CTRL|HOTKEY_SHIFT|65; */ public var hotkey:int=-1; /** @param url This is the file you are linking _to_. Remember to include the file: url scheme if it's a local file e.g. new WindowsURLShortcut("file:///C:/Windows/notepad.exe");*/ public function WindowsURLShortcut(url:String) { this.url=url; } public function write(file:File):void { var stream:FileStream=new FileStream(); stream.open(file,FileMode.WRITE); // It's a UTF-8 file - write the BOM stream.writeByte(239); stream.writeByte(187); stream.writeByte(191); stream.writeUTFBytes("[InternetShortcut]"+"\r\n"); stream.writeUTFBytes("URL="+url+"\r\n"); if (workingDirectory!=null) stream.writeUTFBytes("WorkingDirectory="+workingDirectory+"\r\n"); stream.writeUTFBytes("ShowCommand="+showCommand+"\r\n"); stream.writeUTFBytes("IconIndex="+iconIndex+"\r\n"); if (iconFile!=null) stream.writeUTFBytes("IconFile="+iconFile+"\r\n"); if (hotkey!=-1) stream.writeUTFBytes("HotKey="+hotkey+"\r\n"); stream.close(); } } }