Windows Mobile .NET version detection at install
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:
//
#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,
®Key
);
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;
}