Using Custom Icons in Windows Mobile 6.5

Update: Updated sample code, you can download it here. Read all about it here.

If you’ve seen the any of the plethora of Windows Mobile 6.5 screen shots, likely you’d agree that it looks much better than previous versions. A component of this ‘face lift’, is support for PNG files in the Window Mobile 6.5 Start screen. Including a nicely rendered PNG file as your application icon is important to ensure the highest quality user experience across different devices.

If you plan to distribute your application via Windows Marketplace for Mobile (and I don’t know why you wouldn’t) the requirements document requires that you use a 90 x 90 Start screen icon for your application. This post will cover how to use PNG files as icons in the Windows Mobile 6.5 Professional Start screen. For information on creating PNG icons, see my previous post on Creating Custom Icons for Windows Mobile 6.5. The sample code I will be referring to in this post can be found here.

Contents:

Start Screen: Resolution / DPI and Icon Size
Registry Keys
Setup: Static or Dynamic
Cached Icons
Games Shortcuts Folder

Start Screen: Resolution / DPI and Icon Size

The Start Screen is one of the huge improvements in Windows Mobile 6.5 Professional. This replaces the Start Menu in previous versions. The improvements include: enhanced touch screen navigation (tap, tap and hold, pan, and flick) and more options for organizing and presenting Start menu items. image

If you are an experienced Windows Mobile developer, you know that depending on the DPI and resolution of the device, the shell extracts the appropriately sized icon from the EXE for display in the Start screen. Windows Mobile 6.5 still supports this; however now it also supports the display of PNG file icons. The shell does not automatically select the size of the PNG icon based on the device DPI. This dynamic selection of the icon is done in a setup dll. (See dynamic setup below.) However, if you do not want to provide a separate PNG file for each DPI, you can provide one (90×90) and the shell will scale down the icon as necessary, depending on the DPI of the device. (In fact, this is the Marketplace requirement.) The table below illustrates the DPI / resolution and icon size relationship. 

 


Windows Mobile Platform Resolution DPI Orientation Small Icon Large Icon Start Menu PNG Icon (6.5)
6.x Professional 240×240 96 Square 16×16 32×32 45×45
6.x Professional 240×320 96 Portrait & Landscape 16×16 32×32 45×45
6.x Professional 240×400 96 Portrait & Landscape 16×16 32×32 45×45
6.x Professional 320×320 128 Square 21×21 43×43 60×60
6.x Professional 480×480 192 Square 32×32 64×64 90×90
6.x Professional 480×640 192 Portrait & Landscape 32×32 64×64 90×90
6.x Professional 480×800 192 Portrait & Landscape 32×32 64×64 90×90
6.x Professional 480×864 192 Portrait & Landscape 32×32 64×64 90×90
6.x Standard 176×220 96 Portrait 16×16 32×32 N/A
6.x Standard 240×320 131 Portrait & Landscape 22×22 44×44 N/A
6.x Standard 240×240 131 Square 22×22 44×44 N/A
6.x Standard 240×400 131 Portrait & Landscape 22×22 44×44 N/A
6.x Standard 440×240 131 Landscape 22×22 44×44 N/A

 

Registry Keys

To have the Start screen use a PNG file instead of an icon embedded in the EXE, you need to provide the following registry entries:

[HKEY_LOCAL_MACHINESecurityShellStartInfoStartPhone.lnk]
"Icon"="Application DataMy Appnewphoneicon.png"

Here are the definitions of the value pair settings:

Name Type Description
Name REG_SZ Specifies the display name of the item. If the value is not specified, the file name will be displayed without the extension.
Group REG_DWORD Specifies whether the item is a folder. The value can be set to TRUE or FALSE. Set the value to TRUE to indicate that the item is a folder. If the value is not specified, the system will determine the Group value by verifying whether the registry key has any subkeys.
Icon REG_SZ Specifies the path and file name where the icon is located. The icon can consist of a PNG file or an embedded icon resource module. If this value is not specified, the default icon of the shell will be used.
Rank REG_DWORD Specifies the rank of the item. An item that specifies a larger value for Rank will be displayed before items that specify a lower value. If this item is not specified, the Rank will be set to 0.
 

Security note: This requires creating a registry key underneath HKLMSecurity. This is a protected registry location. To write to a protected registry key, the CAB file needs to be signed. This will not be a problem for Marketplace applications, since by definition they are signed. As mentioned, this article only applies to Windows Mobile Professional devices. However, if you use the same CAB for a Standard device installation, you will need to make sure your application is signed privileged, otherwise setup will fail. To avoid having to sign your CAB privileged (and incur the extra Marketplace approval time this requires) you can use the dynamic setup mentioned in this post. Be sure to include in your setup dll, the conditional creating of the StartInfo registry key and copying of the PNG file, and only do these steps if installing on a Professional device.  See the sample code here for an example on how to do this.

Setup

In the next two sections, I’ll walk through two deployment scenarios, static and dynamic.

Static Setup:

You can specify the registry key as part of your CAB file configuration. Per the Marketplace requirements, I will use a 90 x 90 PNG file as the Start screen icon. In my Smart Device CAB project, I have added the following registry key:

image_thumb7

Note: This registry key supports ‘CE strings’ and .INF file strings. Above %InstallDir% maps to the ‘Program FilesSMS Intercept’ directory.

My CAB file also includes the (90×90) AppIcon.png and a shortcut of the same name as the registry key above (SMS Intercept.lnk). See below:

image_thumb2

Dynamic Setup:

Detecting DPI:

Another way to configure the Start screen icon is dynamically: copying the appropriately sized PNG file based on the DPI of the device. We will use a setup dll to detect the DPI, and copy the appropriate PNG. You may know that WCELOAD (the EXE that process the CAB file) or a DLL that is loaded into its process, will return the same DPI (96) no matter the actual DPI of the device. To workaround this, we launch a very small helper EXE that quickly exits, without UI, and returns the DPI. The SDK sample ResDLL uses this technique as well as demonstrates how to install DPI specific resource DLLs. Here is the code used to detect the DPI:

int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
HDC hdc = ::GetDC(NULL);
INT ans = ::GetDeviceCaps(hdc, LOGPIXELSX);
::ReleaseDC(NULL, hdc);
return ans;
}
Copy DPI specific files:

Our dynamic CAB file contains four png files:

        45.png

        60.png

        90.png

        AppIcon.png

Based on the DPI detected, we copy the appropriate PNG file to the filename AppIcon.png. AppIcon.png is included in the CAB as a fallback in case our DPI detect logic fails. The unused icons and the DPI detect EXE are deleted.

Here is a code snippet from the sample setup dll (SetupDPI) implementing this:

wsprintf(szFile,_T("%s%s"), pszInstallDir, _T("GetRealDPI.EXE"));
// Launch DPI Detector
::CreateProcess(szFile, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, &pi);
::WaitForSingleObject(pi.hProcess, 10000);
// DPI is returned in exit code of detector app
::GetExitCodeProcess(pi.hProcess, &nSystemDPI);
::CloseHandle(pi.hProcess);
::DeleteFile(szFile);

// Based on DPI, copy xx.png to AppIcon.png and delete unused files
wsprintf(szOutFile,_T("%s%s"), pszInstallDir, szTargetFilename);
for (INT i=0;i<ARRAYSIZE(DPI_Icon);i++) {
wsprintf(szFile,_T("%s%s"), pszInstallDir, DPI_Icon[i].lpstrIconSize);
if (DPI_Icon[i].DPI==nSystemDPI) {
::CopyFile(szFile, szOutFile, FALSE);
}
::DeleteFile(szFile);
}

Create Shortcut:

As mentioned, we do the post-processing of the files after the CAB is installed (in the Install_Exit function). That is, because the icon image in the Start screen is created when the shortcut is created (see the cached icons section below), we need to create the shortcut in the setup dll instead of in the CAB file as was done in the static CAB sample. Otherwise, the Start screen will use an icon extracted from the EXE instead of the PNG file. Here is the language independent code that creates the shortcut:

// Build lnk filename
PTCHAR pAppDir = wcsrchr(pszInstallDir, '');
TCHAR szShortcutPath[MAX_PATH];
// CSIDL_PROGRAMS == WindowsStart MenuPrograms
SHGetSpecialFolderPath(hwndParent, szShortcutPath, CSIDL_PROGRAMS , false);
wsprintf(szFile,_T("%s%s%s"), szShortcutPath, pAppDir, _T(".lnk"));

// Build exe filename
// CSIDL_PROGRAM_FILES == Program Files
SHGetSpecialFolderPath(hwndParent, szShortcutPath, CSIDL_PROGRAM_FILES , false);
wsprintf(szOutFile,_T(""%s%s%s%s""),
     szShortcutPath, pAppDir, pAppDir, _T(".exe"));

SHCreateShortcut(szFile, szOutFile);
 
Note that the dynamic CAB sample does not not contain the file system declaration that creates a shortcut as the static sample CAB does.

Cached Icons

During development, you will likely want to change the PNG file as you experiment will different artwork. You will notice that if you overwrite the PNG file, the Start screen will not use the new image. This is because when the Start screen shortcut is created, the icon image is cached by the shell. Thereafter for better performance, the shell retrieves the image from the cache. The cache is rebuilt a boot time. Here is one possible workaround:

  1. Delete the shortcut
  2. Rename (or copy) target EXE name. For example, rename hello.exe to hello1.exe
  3. Recreate shortcut pointing to new EXE name.

Here is provisioning XML that does this. You can run this using RapiConfig.exe:

<wap-provisioningdoc>
<characteristic type="FileOperation">
<!-- Delete Shortcut -->
<characteristic type="%CE11%SMS Intercept.lnk" translation="install">
<characteristic type="Delete">
<parm name="ForceDelete"/>
</characteristic>
</characteristic>

<!-- Copy EXE name to new EXE -->
<characteristic type="%CE1%sms Interceptsms Intercept1.exe"
          translation="install">
<characteristic type="Copy">
<parm name="Source" value="%CE1%sms Interceptsms Intercept.exe"
          translation="install"/>
</characteristic>
</characteristic>

<!-- Create new shortcut pointing to new EXE name -->
<characteristic type="%CE11%" translation="install">
<characteristic type="MakeDir" />
<characteristic type="SMS Intercept.lnk" translation="install">
<characteristic type="Shortcut">
<parm name="Source" value="%CE1%sms Interceptsms Intercept1.exe"
translation="install" />
</characteristic>
</characteristic>
</characteristic>
</characteristic>
</wap-provisioningdoc>

Games Shortcuts Folder

If we were installing this application into the Games folder, the key pointing to the PNG file would look like this:
[HKEY_LOCAL_MACHINESecurityShellStartInfoStartGamesPhone.lnk]
"Icon"="Application DataMy Appnewphoneicon.png"

Game developers have raised the question, “How do I create the Games registry key in a language independent way?” Without the Games folder, this key is language independent. However, the shell will look for the shortcut (.lnk) files in the directories below Start, therefore we need to setup this key using the localized name for Games. This requires a Setup DLL. See the sample code for this post here.

To have your shortcut created in the Games folder, you must change the following line in the SetupDPI.CPP and rebuild the project:

// Set this to true to create shortcut and 
// registry key in the localized 'Games' Folder
BOOL g_bCreateInGamesFolder=FALSE;

Conclusion

You should now understand how to configure your CAB file projects to include PNG files as icons in the Windows Mobile 6.5 Start screen.

For a list of frequently asked questions on this topic see here: Start Screen PNG Icon FAQ