Windows Mobile .NET version detection at install

December 7, 2009 by admin
Filed under: C#, MS Mobile, Programming 

Question: When I install my Windows Mobile application on device not having NET CF 3.5, it fails to run. What to do?

When you create a cabinet (.cab) file, you can choose to add an optional tailor-made setup.dll file to check out the version of OS and .NET framework.

See http://msdn.microsoft.com/en-us/library/aa924308.aspx.

Packaging a Smart Device Solution for Deployment: http://msdn.microsoft.com/en-us/library/zcebx8f8(VS.80).aspx

Insert a version detection function into yours Install_Init() method. See our sample code below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Setup.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include "ce_setup.h"
#include "Setup.h"

#define MIN_DOTNETCF_VERSION    3

BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

// ----------------------------------------------------------
// Variables

TCHAR ErrorMessageTitle[] = _T("RandomFacts Setup Error");

TCHAR ErrorMessageNet[] =  _T("Microsoft Windows Mobile 6.0+ and NET CF 3.5+ are required to run our applications.\n")
                           _T("You can download the latest updates from Microsoft.\n")
                           _T("Visit http://www.microsoft.com/windowsmobile for details.\n");

// ----------------------------------------------------------
// This function will be called when the user
// tries to install the cab. According to its return
// value the installation continues or is cancelled.
// As this could be called more than once
// (i.e. if there is not enough space on the target)
// we should take care about fFirstCall parameter
// to show the dialog only once.
// To continue installation, return codeINSTALL_INIT_CONTINUE
// If you want to cancel installation,
// return codeINSTALL_INIT_CANCEL

codeINSTALL_INIT Install_Init(HWND hwndParent, BOOL  fFirstCall, BOOL fPreviouslyInstalled, LPCTSTR pszInstallDir )
{

      if( fFirstCall ){
        if( ::IsDotNetInstalled(MIN_DOTNETCF_VERSION) == false ){
            ::MessageBox(hwndParent, ErrorMessageNet, ErrorMessageTitle, MB_OK);
            return codeINSTALL_INIT_CANCEL;
        }
    }

    return codeINSTALL_INIT_CONTINUE;
}

// ----------------------------------------------------------
// Queries the registry to see if .NET 3.0 or above is installed
bool IsDotNetInstalled(int MinMajorVer)
{
    HKEY        regKey;
    TCHAR       achKey[MAX_KEY_LENGTH];   // buffer for subkey name
    DWORD       cbName;                   // size of name string
    TCHAR       achClass[MAX_PATH] = TEXT("");  // buffer for class name
    DWORD       cchClassName = MAX_PATH;  // size of class string
    DWORD       cSubKeys=0;               // number of subkeys
    DWORD       cbMaxSubKey;              // longest subkey size
    DWORD       cchMaxClass;              // longest class string
    DWORD       cValues;              // number of values for key
    DWORD       cchMaxValue;          // longest value name
    DWORD       cbMaxValueData;       // longest value data
    DWORD       cbSecurityDescriptor; // size of security descriptor
    FILETIME    ftLastWriteTime;      // last write time
    LPDWORD     data;
 
    DWORD       i, retCode;
 
    TCHAR       achValue[MAX_VALUE_NAME];
    DWORD       cchValue = MAX_VALUE_NAME;

    LONG result = RegOpenKeyEx(
                              HKEY_LOCAL_MACHINE,
                              _T("Software\\Microsoft\\.NETCompactFramework"),
                              0,
                              0,
                              &regKey
                               );

    if (result == ERROR_SUCCESS){                      
        // Get the class name and the value count.
        retCode = RegQueryInfoKey(
                                    regKey,                  // key handle
                                    achClass,                // buffer for class name
                                    &cchClassName,           // size of class string
                                    NULL,                    // reserved
                                    &cSubKeys,               // number of subkeys
                                    &cbMaxSubKey,            // longest subkey size
                                    &cchMaxClass,            // longest class string
                                    &cValues,                // number of values for this key
                                    &cchMaxValue,            // longest value name
                                    &cbMaxValueData,         // longest value data
                                    &cbSecurityDescriptor,   // security descriptor
                                    &ftLastWriteTime);       // last write time                    
   
        // Enumerate the key values.
        if (cValues)
        {          
            for (i=0, retCode=ERROR_SUCCESS; i<cValues; i++)
            {                  
                cchValue = MAX_VALUE_NAME;
                achValue[0] = '\0';
                retCode = RegEnumValue(regKey, i,
                                        achValue,
                                        &cchValue,
                                        NULL,
                                        NULL,
                                        NULL,
                                        NULL); 

                if (achValue[0] >= '0' && achValue[0] <= '9')
                {
                    int digit = achValue[0] - '0';
                    if (digit >= MinMajorVer)      // Above MinMajorVer
                    {
                        return true;
                    }
                }
            }
        }
    }
    return false;
}

If you want to sell your app on the Windows Marketplace, you don’t need to take care about the required .NET CF versions. Microsoft did a great job here.