Erwin's blog
Programmatically instantiate the password login dialog
In Windows CE there is built in functionality that allows a user to lock and login the system, just like you are used to on "big" desktop systems. To activate this functionality you simply set the system password in Windows CE through the control panel applet. You can also do this programmatically using the SetPassword() and SetPasswordStatus() API's.
When the password is set at boot the system will show the standard Windows CE login screen:

Recently I got a question whether it is possible to programmatically bring up the password dialog. After some analysis the answer was yes. I found out that the Power Manager instantiates the password dialog when the system returns from showing a screensaver. The password dialog is instantiated by calling ShowStartupWindow(). Here's the code used by the Power Manager (from "<WINCEROOT>\PUBLIC\COMMON\OAK\DRIVERS\PM"):
gpfnShowStartupWindow = (PFN_ShowStartupWindow) GetProcAddress(hmCoreDll, _T("ShowStartupWindow"));
The example below shows you how to use the exact same technique inside your applications to instantiate the password dialog:
// We need to declare these functions here because they are defined
// in pwinbase.h (contrary to what MSDN help for "SetPassword" tells
// us!) and pwinbase.h is not included as an SDK header file.
// Therefore to use these functions without needing access to all
// Platform Builder include files, we have to define them ourselves.
extern "C"
{
BOOL SetPassword (LPWSTR lpszOldpassword, LPWSTR lspzNewPassword);
BOOL SetPasswordStatus(DWORD dwStatus, LPWSTR lpszPassword);
}
// Forward declarations
bool InitPassword(LPWSTR pszOldPassword, LPWSTR pszNewPassword);
// Defines
#define PASSWORD_STATUS_ACTIVE 1
#define PASSWORD_STATUS_SCREENSAVERPROTECT 2
// Typedef'ed functions
typedef BOOL (WINAPI *PFN_ShowStartupWindow)(void);
int _tmain(int argc, _TCHAR* argv[])
{
BOOL bRet = false;
HMODULE hCoreDll = NULL;
PFN_ShowStartupWindow pfnShowStartupWindow = NULL;
// Create and activate password
// (you can supply the current ("old") password on the command line)
LPWSTR pszOldPassword = (argc > 1) ? argv[1] : NULL;
if (InitPassword(pszOldPassword, L"password"))
{
hCoreDll = (HMODULE) LoadLibrary(L"coredll.dll");
if (hCoreDll)
{
pfnShowStartupWindow = (PFN_ShowStartupWindow)GetProcAddress(hCoreDll, L"ShowStartupWindow");
if (pfnShowStartupWindow)
bRet = pfnShowStartupWindow();
else
RETAILMSG(1, (L"Failed to get address of \"ShowStartupWindow\" in coredll.dll, error %d\r\n", GetLastError()));
FreeLibrary(hCoreDll);
}
else
RETAILMSG(1, (L"Failed to load coredll.dll, error %d\r\n", GetLastError()));
}
return (int)bRet;
}
bool InitPassword(LPWSTR pszOldPassword, LPWSTR pszNewPassword)
{
bool bRet = false;
// Please note that the password must be lower case when you set it!
// The password dialog box (code in startui.cpp) always converts the
// user entered password to lower case before the compare!
if (!SetPassword(pszOldPassword, pszNewPassword))
RETAILMSG(1, (L"Failed to set the password, error %d\r\n", GetLastError()));
//Set the password status
else if (!SetPasswordStatus(PASSWORD_STATUS_ACTIVE | PASSWORD_STATUS_SCREENSAVERPROTECT, pszNewPassword))
RETAILMSG(1, (L"Failed to set the password status, error %d\r\n", GetLastError()));
else
bRet = true;
return bRet;
}
Of course you can always create your own password dialog (because let's be honest; it's not the most beautiful dialog you've ever seen, right?!), but if you don't mind the ugly box the technique above just uses the existing functionality of CE and will save you a bit of time developing a password dialog yourself.
From the comments in the code above you can see I found a rather interesting little fact: Windows CE passwords are CASE INSENSITIVE! That's old-school, isn't it?!
The code that handles the GUI portion of the password handling code is in startui.cpp (here "<WINCEROOT>\PUBLIC\COMMON\OAK\DRIVERS\STARTUI"):
SendMessage(hwndPass, WM_GETTEXT, PASSWORD_LENGTH + 1, (LPARAM)szText);
_wcslwr(szText);
isAuthValid = (CheckPassword(szText) != FALSE);
The _wcslwr function converts the password string to lowercase before checking it, but SetPassword allows you to set a password using mixed case! Keep that in mind next time you locked yourself out of your Windows CE device... ;o)
SD MMC and Windows CE
Lately there have been a lot of questions about SD and MMC in the newsgroups, especially about what is supported by the Microsoft SD bus driver. This blog post hopefully helps clear up some things about SD/MMC support in Windows CE.
First let’s look at an overview of the MMC and SD specifications and who supports what:
| CE Version | SD Spec | MMC Spec |
|---|---|---|
| Win CE 5.0 RTM | 1.1 | 3.x |
| Win CE 5.0 QFE (April 2007 onward) | 2.0 | 4.3 |
| Win Mobile 6.0 RTM | 1.1 | 3.x |
| Win Mobile 6.x (AKU 0.2 onward) | 2.0 | 4.3 |
| Win CE 6.0 RTM | 1.1 | 3.x |
| Win CE 6.0 R2 | 2.0 | 4.3 |
From the table above it looks like the SD bus driver in CE 6.0 R2 supports the MMC 4.3 specification, but actually it doesn’t completely (as we’ll see a bit later in this blog post).
The Microsoft SD bus driver (sdbus2.dll) is fully supporting the SD 2.0 specification. Because the MMC 4.3 specification is quite similar to SD 2.0, CE “somewhat” supports MMC 4.3.
So what does this mean? Well, for example, the number of data lines (bus width) of MMC supported by the Microsoft SD bus driver differs from the MMC specification:
8/4 or 1-bit mode
The MMC specification tells us it supports 8-bit wide bus mode (8-data lines). However, the SD 2.0 specification does not support 8 bit bus mode. Since CE officially supports SD but not MMC, CE does not support the 8-bit mode for any MMC/SD card. Unfortunately it appears the 4-bit mode is also not supported for MMC cards by the Microsoft SD bus driver even though the SD specification does support this mode. This leaves 1-bit mode as the only supported mode for MMC.
Here’s an overview of the supported modes by the SD bus driver (sdbus2.dll):
| Bus mode | SD | MMC |
|---|---|---|
| 1 | Y | Y |
| 4 | Y | N |
| 8 | N | N |
So does this mean that MMC cannot support 4 or 8 bit at all? Well no, not really... You can always CLONE the SDBUS driver and modify it according to your needs or you can develop your own driver without using the SD bus driver at all.
High Capacity
According to the SD 2.0 specification "High Capacity" means cards with sizes larger then 2GB. SDHC cards are supported by the SD bus driver version 2.0. However, because of a bug in the SD bus driver high capacity MMC cards don’t work. You need to fix one line of code to support HC MMC cards. Besides this bug there is also a difference in the protocol for MMC and SD 2.0 regarding High Capacity, more about that later.
First let’s fix the obvious bug so that your High Capacity MMC card will be recognized and mounted properly:
The first step is to clone the SD Bus driver located at <WINCEROOT>\PUBLIC\COMMON\OAK\DRIVER\SDCARD\SDBUS
- Open a build release window
- Type "
cd %_targetplatroot%" - Type "
cd src" - Type "
cd drivers" - Type "
md sdbus2" - Type "
cd sdbus2" - Type "
sysgen_capture -p common sdbus" - Now copy the files from
<WINCEROOT>\PUBLIC\COMMON\OAK\DRIVER\SDCARD\SDBUSinto<WINCEROOT>\PLATFORM\<YourBSP>\SRC\DRIVERS\SDBUS2 - And merge
sources.sdbusandsourcesso you end up with this sources file: - Try to build the SDBUS2 driver; it should build without errors. If it doesn’t, make sure you selected the SD Bus Driver in the catalog and performed a sysgen on your OSDesign.
- And add the SDBUS2 folder to the
dirsfile in theDRIVERSfolder. - Don't forget to change any BSP component that links to
$(_COMMONOAKROOT)\lib\$(_CPUINDPATH)\sdbus.libto use the cloned SDBUS library, located at$(_TARGETPLATROOT)\lib\$(_CPUINDPATH)\sdbus.lib
TARGETNAME=sdbus
TARGETDEFNAME=SDBus2
DEFFILE=$(TARGETDEFNAME).def
TARGETTYPE=DYNLINK
RELEASETYPE=PLATFORM
DLLENTRY=_DllEntryCRTStartup
SOURCES = sdbusreq.cpp \
sddevice.cpp \
sdbus.cpp \
sdslot.cpp \
sdclient.cpp \
sddevinf.cpp \
sdiofeat.cpp \
sdworki.cpp \
sddebug.cpp \
TARGETLIBS= \
$(_SYSGENOAKROOT)\lib\$(_CPUINDPATH)\defbuslib.lib \
$(_SYSGENSDKROOT)\lib\$(_CPUINDPATH)\coredll.lib \
$(_SYSGENOAKROOT)\lib\$(_CPUINDPATH)\ceddk.lib
Note that I added SYNCHRONIZE_BLOCK=1 to make sure any other component that will link to the sdbus library will be able to find it. SYNCHRONIZE_BLOCK=1 makes sure this folder is built before any other folder in the DRIVERS folder is built.
Now change StringCchCopy to StringCchCat in line 1394 of sddevice.cpp (in your cloned folder of course!). This will append the "\\High_Capacity" string to the Client driver registry entry instead of replacing it (which leads to not finding the correct registry path for the profile because "HKLM\\High_Capacity" is not a valid registry path). Even with this fix it won’t find that path because Microsoft did not provide registry settings for High Capacity MMC. Let’s fix that by adding the following to platform.reg:
[HKEY_LOCAL_MACHINE\Drivers\SDCARD\ClientDrivers\Class\MMC_Class\High_Capacity]
"Dll"="SDMemory.dll"
"Prefix"="DSK"
"BlockTransferSize"=dword:40 ; send no more than 64 blocks of data per bus transfer
;"SingleBlockWrites"=dword:1 ; alternatively force the driver to use single block access
;"IdleTimeout"=dword:7D0 ; 2000 milliseconds
;"IdlePowerState"=dword:2 ; 0 == D0, 1 == D1, etc.
;"DisablePowerManagement"="" ; if value present, then disable (remove value to enable)
"Profile"="MMC"
"IClass"=multi_sz:"{A4E7EDDA-E575-4252-9D6B-4195D48BB865}",
"{8DD679CE-8AB4-43c8-A14A-EA4963FAA715}"
Now you can Build and Sysgen your BSP by right clicking on your BSP node in the Solution Explorer and choosing Build and Sysgen. NEVER EVER click Build and Sysgen from the Build menu, please read the blog post http://www.guruce.com/blogpost/whattobuildwhen to understand why you should delete that option from the build menu. After the Build and Sysgen of the BSP perform a Copy files to release directory followed by a Make image and download your kernel to your device. When you now insert a high capacity MMC card it should be recognized and mounted correctly, well, almost! The size is most probably still reported wrong. This is because of a difference in the protocol. CMD 8 is handled differently in the SD 2.0 and MMC 4.3 specification:
| Command | Type | Response | Abbreviation | Command Description |
|---|---|---|---|---|
| CMD8 | MMC | R1 | SEND_EXT_CSD | The card sends its EXT_CSD register as a Block of data. |
| CMD8 | SD | R7 | SEND_IF_COND | Sends SD Memory Card interface condition |
In the SD protocol CMD8 is used to identify high capacity cards and it is send at the beginning of the initialization process. When CMD8 is getting a response it means that it is identified as a High Capacity card. If sending a CMD8 results in a response timeout it is not a High Capacity card.
For MMC the CMD8 means retrieving the density of the card from the EXT_CSD register instead of the CDS register. CMD8 must be send after a CMD7 command which will place the card into "Tran" state. Since the SD bus driver doesn't do that the CMD8 will time out.
Like I said the SD bus driver fully supports the SD 2.0 specification and it reads the card density from the CSD register. This works for SD 2.0, but not for MMC. To fully support High Capacity MMC cards you should modify the SD bus driver so it can handle CMD8 instead of CMD9 to retrieve the card density for MMC high capacity cards.
SDBUS or SDBUS2
Now how do you select the correct SD bus driver? First remember that you have to install the correct version of Windows CE and install all required QFEs (see specification overview above). For Windows Embedded CE 6.0 there are two catalog components for SDBUS; "SD Bus Legacy" and "SD Bus driver". The legacy one is the SD bus driver that supports SD specification 1.1 and the "SD Bus Driver" item supports the 2.0 specification.
For all other versions of CE there is only one catalog component which automatically selects the SD bus 1.1 specification. To support the 2.0 specification in CE versions prior to CE 6.0 you have to set the IMGSDBUS2 environment variable to 1.
Conclusion
Windows CE fully supports the SD 2.0 specification, but as we saw this doesn’t automatically mean it also fully supports High Capacity MMC cards. Fortunately with a couple modifications here and there you can now fully support High Capacity MMC cards as well!
Command Line Build
This post will show you how to create a batch file that will build your Windows CE OS without using the Visual Studio/Platform Builder IDE.
Often the question is asked how to setup an environment which automatically extracts all information from version control and then builds your code. There are a lot of tools that can help you do that: an open source alternative can be found at http://cruisecontrol.sourceforge.net.
To build your kernel without having to use the IDE create a batch file with the following content:
SET _WINCEROOT=C:\WINCE500
SET _OSDESIGNDIR=%_WINCEROOT%\PBWorkspaces\YOUR_WORKSPACE_FOLDER
SET _OSDESIGN=%_OSDESIGNDIR%\YOUR_WORKSPACE_FILE.pbxml
SET _OSDESIGNCONFIG=YOUR_OSDESIGN_CONFIG_NAME
"%ProgramFiles%\Windows CE Platform Builder\5.00\CEPB\BIN\pbxmlutils" /getbuildenv /workspace "%_OSDESIGN%" /config "%_OSDESIGNCONFIG%" > SetEnv.bat
cd "%_OSDESIGNDIR%"
call SetEnv.bat
delete SetEnv.bat
cd "%_OSDESIGNDIR%"
blddemo clean -q
Note that for CE 6.0 pbxmlutils is located in "%ProgramFiles%\Microsoft Platform Builder\6.00\cepb\IdeVS\" and you use SET _WINCEROOT=C:\WINCE600
You need to replace the first 3 SET variables to match your specific project:
YOUR_WORKSPACE_FOLDER: Workspace folder which is located under the PBWorkspaces (CE 5.0) or OSDesigns (CE 6.0) folder. This is the folder that contains YOUR_WORKSPACE_FILE.
YOUR_WORKSPACE_FILE: The name of your OS Design workspace; the file with extension .pbxml. This file is located in YOUR_WORKSPACE_FOLDER.
YOUR_OSDESIGN_CONFIG_NAME: This is the configuration name you select in the IDE of Platform Builder, eg Emulator: x86_Release. You can also open your .pbxml file with notepad to find out what the configuration name is (search for Configuration Name).
Happy building!
Windows CE Task Manager
I found a great tool to monitor the CPU load on your Windows CE device, which includes the source code!
