My first post on this blog was about deploying application and I touched briefly on autorun.exe. I have been asked several times to expand on this and go into the details so here it is!

Windows Mobile supports a simple, automated way of installing and uninstalling applications from removable media cards. When an SD card or CF card is inserted into a device the OS catches the hardware event and looks on the storage card for a directory that matches the processor type.

All Windows Mobile devices after Pocket PC 2000 have an ARM V4 instruction set so in general 2577 is all you need to know. Other processor types are useful to know for embedded CE systems, Pocket PC 2000 device and for the current emulators:

ARMV4 (or more accurately SA1100): 2577

X86: 686

ARM 720: 1824

MIPS: 4000

SH3: 10003

If the correct processor specific directory exists the OS looks for a file named 'Autorun.exe' and attempt to copy it to the \windows directory. Once the file is copied it is executed with a single parameter string ‘install’.

The autorun.exe is just a standard PE format executable. You can insert UI if you want, or even write the application in managed code so long as Compact Framework is present on the device.

In many cases the autorun application is used to scan and install CAB files from the inserted card, but beware because the autorun is executed from the \windows directory *not* from the original location. On modern devices it’s quite a challenge to locate the card that was just inserted. There is an api: SHGetAutoRunPath that can help if there is just one card present in the device, but most devices today have more than one expansion slots and often include internal card: these are spare areas of ROM memory, unused by the OS. OEM’s often wrap this spare storage as a flash card for things like data backup.

When a storage card is removed from the device the OS looks in the \windows directory and re-runs autorun.exe but with ‘uninstall’ as a parameter. Once the autorun process has completed, the autorun.exe file is deleted from the device. This is an ideal opportunity to remove applications or to do some tidy-up on the device.

There are a couple of things to be aware of:

1>    If an autorun.exe already exists in the \windows directory when a new card is inserted into the device then no new autorun will be copied into \windows, but the existing autorun will execute! So imagine a device with both SD and CF card slots. SD1 card is inserted and the autorun gets copied and run with ‘install’ parameter. Then CF1 card is inserted but because the SD1 card autorun exists in the windows directory no copy takes place. However the existing SD1 autorun *will* still be run with the ‘install’ parameter. Now remove the CF1 card. The SD1 autorun in the \windows directory will be executed with the ‘uninstall’ parameter and then deleted. Now remove SD1, nothing happens.

2>    Removing or inserting cards while the device is in an ‘off’ state is still picked up when the power is turned back on. The OS then catches up and takes the relevant steps. Obviously if a card is inserted and removed while the power is off, nothing happens.

3>    If the OEM has wrapped up spare flash ROM space as a removable card then it obeys the same rules. Putting \2577\autorun.exe on the internal storage card will cause it to run when that card is ‘inserted’. An internal card is ‘inserted’ when a soft or hard reset takes place. There is no practical way of removing an internal card. This can be a great way of installing apps on hard reset. Be aware that OEM’s have the freedom to implement this behavior differently on their device.

Here is an example of an autorun written in C++ (disclaimer applies):

// Autorun.cpp : Defines the entry point for the application.

//

#include "stdafx.h"

#include "projects.h"         // Defines the ‘project’ api’s like FindFirstFlashCard api’s

 

int WINAPI WinMain(     HINSTANCE hInstance,

                        HINSTANCE hPrevInstance,

                        LPTSTR    lpCmdLine,

                        int       nCmdShow)

{

      if (0==wcscmp(lpCmdLine,L"install"))

      {

 

            MessageBox(NULL,L"About to install, press OK to start",L"Media card install",MB_OK);

            WIN32_FIND_DATA   fflash;

            HANDLE findflash = FindFirstFlashCard(&fflash);

            while (INVALID_HANDLE_VALUE != findflash)

            {

                  TCHAR FileName[MAX_PATH];

                  wsprintf(FileName,L"\\%s\\*.cab",fflash.cFileName);

                  WIN32_FIND_DATA   ffile;

                  HANDLE findfile = FindFirstFile(FileName,&ffile);

                  while (INVALID_HANDLE_VALUE != findfile)

                  {

                        TCHAR fullPath[MAX_PATH];

                        wsprintf(fullPath,L"\\%s\\%s",fflash.cFileName, ffile.cFileName);

 

                        SHELLEXECUTEINFO sei;

                        memset(&sei,0,sizeof(SHELLEXECUTEINFO));

 

                        sei.cbSize = sizeof(SHELLEXECUTEINFO);

                        sei.fMask = 0;              

                        sei.hwnd = NULL;

                        sei.lpVerb = NULL;

                        sei.lpFile = fullPath;

                        sei.lpParameters = L"";

                        sei.nShow = SW_SHOWNORMAL;    

                        ShellExecuteEx(&sei);

 

                        if (!FindNextFile(findfile,&ffile))

                        {

                              FindClose(findfile);

                              findfile = INVALID_HANDLE_VALUE;

                        }

                  }

 

                  // Now install the CPF files

                  wsprintf(FileName,L"\\%s\\*.cpf",fflash.cFileName);

                  findfile = FindFirstFile(FileName,&ffile);

                  while (INVALID_HANDLE_VALUE != findfile)

                  {

                        TCHAR fullPath[MAX_PATH];

                        wsprintf(fullPath,L"\\%s\\%s",fflash.cFileName, ffile.cFileName);

 

                        SHELLEXECUTEINFO sei;

                        memset(&sei,0,sizeof(SHELLEXECUTEINFO));

 

                        sei.cbSize = sizeof(SHELLEXECUTEINFO);

                        sei.fMask = 0;              

                        sei.hwnd = NULL;

                        sei.lpVerb = NULL;

                        sei.lpFile = fullPath;

                        sei.lpParameters = L"";

                        sei.nShow = SW_SHOWNORMAL;    

                        ShellExecuteEx(&sei);

 

                        if (!FindNextFile(findfile,&ffile))

                        {

                              FindClose(findfile);

                              findfile = INVALID_HANDLE_VALUE;

                        }

                  }

 

                  // Look for the next card

                  if (FALSE==FindNextFlashCard(findflash, &fflash))

                  {

                        FindClose(findflash);

                        findflash = INVALID_HANDLE_VALUE;

                  }

            }

      }

      return 0;

}

 

 

Windows Mobile 5.0

Things are a little different with WM5.0 …

With Windows Mobile 5.0 the Autoexec.exe file is copied to a sub directory specific to the storage card name. For example, if the storage card is named: ‘Storage Card2’ then the autoexec.exe is copied to and run from ‘\windows\autorun\Storage Card2’. This means that the OS can track each storage slot individually and avoid the multi card clash.

 

Marcus