How To Create And Use A Setup DLL In Your Windows CE CAB File
- APPLIES TO
- SUMMARY
- MORE INFORMATION
- Part 1: Getting Started
- Part 2: Creating the DLL
- Part 3: Adding the Setup DLL Code
- Part 4: Building the DLL
- Part 5: Adding the DLL to a CAB File
- REFERENCES
APPLIES TO
WinCE CAB Manager
SUMMARY
This article describes how to create a "Setup DLL" for use in a Windows CE CAB file, and how to add the DLL to a CAB file using WinCE CAB Manager.
MORE INFORMATION
When deploying a Windows CE application, there are often times when the developer may wish to perform custom actions during the installation process. For Windows CE devices, this is accomplished by adding a "Setup DLL" to the CAB file used to install the application.
Part 1: Getting Started
A "Setup DLL" is simply a DLL that exports the following four pre-defined functions:
Install_Init
The Install_Init function is called just before the application is installed onto the device, while the Install_Exit function is called once installation is complete. Likewise, the Uninstall_Init function is called just before the application is un-installed, while the Uninstall_Exit function is called after the application has been un-installed.
Install_Exit
Uninstall_Init
Uninstall_Exit
There are a few important things to keep in mind when developing a Windows CE Setup DLL:
The first step, then, is to determine which version(s) of eMbedded Visual C++ you will need to use. If the application is designed for Pocket PC 2003 or later devices, you will need eVC 4.0; for earlier devices, you will need eVC 3.0. Note that it is generally safe to install both versions, so long as the earlier version (3.0) is installed first.
- The DLL must be written and compiled using either eMbedded Visual C++ 3.0 or eMbedded Visual C++ 4.0.
- The DLL must be compiled for each processor type supported by the application.
- Since the compiled DLL is processor-specific, a separate CAB file must be created for each supported processor type.
Next you will need to install the Software Development Kits (SDKs) for each platform you wish to support. Some of these SDKs may be included with the eMbedded Visual Tools download, while others must be downloaded and installed separately.
Part 2: Creating the DLL
Once you have everything in place, you are ready to begin creating your Setup DLL:
At this point, eVC will create the DLL project and open the workspace. By default, it will create a file named "[ProjectName].cpp", where [ProjectName] is the name you specified in step 3 above. The contents of this file should look something like this:
- Open eVC and click on the 'File / New...' menu item.
- Make sure the 'Projects' tab is selected on the 'New' dialog, and select the 'WCE Dynamic-Link Library' option in the listbox on the left.
- Set the 'Project Name' to the name of the DLL you would like to create (i.e. 'SetupDLL').
- Set the 'Location' property to the directory where you would like to create the project.
- Select the CPU type(s) you would like to support, then hit OK.
- When you are asked what kind of DLL you would like to create, select the 'A simple Windows CE DLL project' option and click Finish, then click OK.
Code: #include "stdafx.h"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
Part 3: Adding the Setup DLL Code
Now we need to add the functions required for Windows CE Setup DLLs, as described in Part 1 above. Edit the main source file to look something like this:
Code: #include "stdafx.h"
#include <ce_setup.h>
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved )
{
return TRUE;
}
// Install_Init
codeINSTALL_INIT Install_Init( HWND hwndParent,
BOOL fFirstCall,
BOOL fPreviouslyInstalled,
LPCTSTR pszInstallDir )
{
return codeINSTALL_INIT_CONTINUE;
}
// Install_Exit
codeINSTALL_EXIT Install_Exit( HWND hwndParent,
LPCTSTR pszInstallDir,
WORD cFailedDirs,
WORD cFailedFiles,
WORD cFailedRegKeys,
WORD cFailedRegVals,
WORD cFailedShortcuts )
{
if( cFailedDirs || cFailedFiles || cFailedRegKeys ||
cFailedRegVals || cFailedShortcuts )
{
return codeINSTALL_EXIT_UNINSTALL;
}
return codeINSTALL_EXIT_DONE;
}
// Uninstall_Init
codeUNINSTALL_INIT Uninstall_Init( HWND hwndParent,
LPCTSTR pszInstallDir )
{
return codeUNINSTALL_INIT_CONTINUE;
}
// Uninstall_Exit
codeUNINSTALL_EXIT Uninstall_Exit( HWND hwndParent )
{
return codeUNINSTALL_EXIT_DONE;
}
Next we need to tell the C++ compiler to "export" these functions - that is, to make them available for external applications to call them. To do this, we need to add a "DEF" file:
Once you have created the DEF file, copy the following code into it:
- Click on the 'File / New...' menu item.
- Make sure the 'Files' tab is selected on the 'New' dialog, and select the 'Text File' option in the listbox on the left.
- Set the 'File name' property to the name of your main source file, except with a '.def' file extension. For example, if you set the name of your project to 'SetupDll', enter 'SetupDll.def' as the file name.
- Click OK to create the file and add it to the project.
Code: EXPORTS
Install_Init
Install_Exit
Uninstall_Init
Uninstall_Exit
Now return to the main source file and add any custom code you need. (Note: A discussion of the possible custom code actions and the C++ language in general are beyond the scope of this article. Please refer to the Windows CE / C++ programming information widely available in books and on the Internet for more information.)
Part 4: Building the DLL
Once you have completed all of the preceding steps, you need to build the DLL for each platform and processor type supported by your application:
Note: Some of the Windows CE SDKs may not have the "ce_setup.h" header file in the proper place. If you see any compiler errors related to this file, use your computer's 'Find' feature to locate this file, and copy it into your Setup DLL project directory.
- Click on the 'Build / Set Active Platform...' menu item.
- Select the platform type you would like to build and press OK.
- Click on the 'Build / Batch Build...' menu item.
- In the 'Project configurations' listbox, select all of the 'Release' configurations. Note that you generally do not need to build the 'Debug' configurations, so it is safe to unselect those.
- Click the 'Rebuild All' button.
Part 5: Adding the DLL to a CAB File
The final step in the process is to add the finished Setup DLL to your application CAB file. Start by launching WinCE CAB Manager and creating the CAB file(s) for your application. Make sure to specify the same platform and processor type for each CAB file as you have compiled your Setup DLL for. Then simply click on the 'Cabinet / Setup DLL / Add...' menu item, browse to the location of the appropriate DLL, and click 'Open' to add it to the CAB file.
REFERENCES
Please refer to the Microsoft Mobile & Embedded Developer Center for detailed information on and download links for eMbedded Tools 3.0, eMbedded Visual C++ 4.0 and any Windows CE SDKs you may require.
the other code here
// ************************************************************
// setup.cpp
//
// Implementation of DllMain and setup functions
//
// Copyright 2003 Microsoft Corporation, All Rights Reserved
//
// ************************************************************
#include "stdafx.h"
HINSTANCE g_hinstModule;
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:
// g_hinstModule = (HINSTANCE)hModule;
// break;
// }
return TRUE;
}
// **************************************************************************
// Function Name: Install_Init
//
// Purpose: processes the push message.
//
// Arguments:
// IN HWND hwndParent ?handle to the parent window
// IN BOOL fFirstCall ?indicates that this is the first time this function is being called
// IN BOOL fPreviouslyInstalled ?indicates that the current application is already installed
// IN LPCTSTR pszInstallDir ?name of the user-selected install directory of the application
//
// Return Values:
// codeINSTALL_INIT
// returns install status
//
// Description:
// The Install_Init function is called before installation begins.
// User will be prompted to confirm installation.
// **************************************************************************
SETUP_API codeINSTALL_INIT Install_Init(
HWND hwndParent,
BOOL fFirstCall, // is this the first time this function is being called?
BOOL fPreviouslyInstalled,
LPCTSTR pszInstallDir
)
{
int iReply = IDYES;
iReply = MessageBox(hwndParent,
(LPCTSTR)LoadString(g_hinstModule, IDS_INSTALL_PERMISSION, NULL, 0),
(LPCTSTR)LoadString(g_hinstModule, IDS_PERMISSIONTITLE, NULL, 0),
MB_YESNO | MB_ICONQUESTION);
if (IDNO == iReply)
{
return codeINSTALL_INIT_CANCEL;
}
return codeINSTALL_INIT_CONTINUE;
}
// **************************************************************************
// Function Name: Install_Exit
//
// Purpose: processes the push message.
//
// Arguments:
// IN HWND hwndParent ?handle to the parent window
// IN LPCTSTR pszInstallDir ?name of the user-selected install directory of the application
//
// Return Values:
// codeINSTALL_EXIT
// returns install status
//
// Description:
// Register query client with the PushRouter as part of installation.
// Only the first two parameters really count.
// **************************************************************************
SETUP_API codeINSTALL_EXIT Install_Exit(
HWND hwndParent,
LPCTSTR pszInstallDir, // final install directory
WORD cFailedDirs,
WORD cFailedFiles,
WORD cFailedRegKeys,
WORD cFailedRegVals,
WORD cFailedShortcuts
)
{
// PROCESS_INFORMATION pi = {0};
// DWORD dwRes = 0;
// codeINSTALL_EXIT cie = codeINSTALL_EXIT_UNINSTALL;
if( cFailedDirs || cFailedFiles || cFailedRegKeys ||
cFailedRegVals || cFailedShortcuts )
{
return codeINSTALL_EXIT_UNINSTALL;
}
return codeINSTALL_EXIT_DONE;
//Error:
// return cie;
}
// **************************************************************************
// Function Name: Uninstall_Init
//
// Purpose: processes the push message.
//
// Arguments:
// IN HWND hwndParent ?handle to the parent window
// IN LPCTSTR pszInstallDir ?name of the user-selected install directory of the application
//
// Return Values:
// codeUNINSTALL_INIT
// returns uninstall status
//
// Description:
// Query the device data using the query xml in the push message,
// and send the query results back to the server.
// **************************************************************************
SETUP_API codeUNINSTALL_INIT Uninstall_Init(
HWND hwndParent,
LPCTSTR pszInstallDir
)
{
int iReply = IDYES;
PROCESS_INFORMATION pi = {0};
DWORD dwRes = 0;
codeUNINSTALL_INIT cui = codeUNINSTALL_INIT_CANCEL;
iReply = MessageBox(hwndParent,
(LPCTSTR)LoadString(g_hinstModule, IDS_UNINSTALL_PERMISSION, NULL, 0),
(LPCTSTR)LoadString(g_hinstModule, IDS_PERMISSIONTITLE, NULL, 0),
MB_YESNO | MB_ICONQUESTION);
if (IDNO == iReply)
{
goto Error;
}
if (FALSE == CreateProcess(TEXT("cfgclient.exe"), TEXT("/unregister"), NULL, NULL, NULL, 0, NULL, NULL, NULL, &pi))
{
goto Error;
}
dwRes = WaitForSingleObject(pi.hProcess, REGISTER_WAIT_TIME);
if (WAIT_OBJECT_0 != dwRes)
{
goto Error;
}
// Registered...Check result.
if (FALSE == GetExitCodeProcess(pi.hProcess, &dwRes))
{
goto Error;
}
ASSERT(STILL_ACTIVE != dwRes);
if (0 != dwRes)
{
goto Error;
}
cui = codeUNINSTALL_INIT_CONTINUE;
Error:
return cui;
}
// **************************************************************************
// Function Name: Uninstall_Exit
//
// Purpose: processes the push message.
//
// Arguments:
// IN HWND hwndParent ?handle to the parent window
//
// Return Values:
// codeUNINSTALL_EXIT
// returns uninstall status
//
// Description:
// Query the device data using the query xml in the push message,
// and send the query results back to the server.
// **************************************************************************
SETUP_API codeUNINSTALL_EXIT Uninstall_Exit(
HWND hwndParent
)
{
return codeUNINSTALL_EXIT_DONE;
}