Blog

I've worn out the newsgroups...

Yes, it's official: I've posted too many answers to the newsgroups in the past 9 years.

They blacklisted me! No, just kidding (I hope). I'm not sure what is going on, but the reason for me being really quiet on the newsgroups is because my posts seem to be blocked by the NNTP server...

If I try to post using any newsreader (I use Thunderbird but also tried Agent) my posts get sent correctly but never appear on the server. If I try to post using the web front-end on microsoft.com, my posts do show up on the web front-end but again never make it to the NNTP server (so they are not being propagated to my (and your) newsreader and also don't appear in Google's Group archive/DejaNews). I've even tried the shadowing news server of my ISP provider. My posts do show up on the news server of my provider, but again don't make it to the news.microsoft.com server.

For example these posts are on the web, but not on the NNTP server:
how to use .CAB file provided by driver vendor
USB unmount in CE 6.0
QFE updates
Strange PM timeouts behaviour

And since nobody is responding to my posts I can only conclude nobody is actually using the web front-end on microsoft.com, well, except for this user (because he responded to my post, yeah!):
Parallel port interrupt

So it all points to me being blacklisted... Maybe there's a spam rule: "if [user's post count] > 10000; "it must be a spambot; block it!"

Microsoft is looking into it, so hopefully I'm back soon...

If you have seen the same behavior or may know what's going on, please leave a comment or send me an email (through the contact form on this site)

UPDATE: It indeed seems to be a spam filter thing. I tried changing my email address but that didn't seem to help. Then I tried changing my "Display Name" as well and now I can post again. If you find yourself unable to post; change both your email address (you don't want to use your real email address on NG's anyway because of email-harvester-bots) and your display name and you should be good to go again!

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"):

hmCoreDll = (HMODULE) LoadLibrary(_T("coredll.dll"));
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:

#include <windows.h>

// 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"):

//      Get text from password window.
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)

PB 5.0 crash hang dead

Today all of a sudden Platform Builder 5.0 didn't want to load my workspace anymore. Just before I updated the machine using Windows Update so I figured it must have had something to do with that. Platform Builder would start loading the workspace, show "Refreshing the Catalog" in the status bar, then show "Getting variables that correspond with catalog items" and then it would just sit there consuming 50% CPU and not responding to anything else. Luckily I'm using VMWare for all my CE development work so it was easy to revert back to an earlier snapshot before I updated XP. Unfortunately, this didn't solve the problem! I continued my search and after some frustrating hours I found the cause:

A bit earlier in the day I added a whole lot of header files (121 to be precise) to one of my subprojects sources file (using the FILE_VIEW_INCLUDES_FOLDER macro), and this proved to be the problem. After I reverted the sources file back to its previous revision in SVN the project loaded again.

Another one of those Platform Builder 5.0 mysteries solved...

Manual Clone of Public Code

If sysgen_capture doesn't work for some reason you can always manually clone the component you want to modify. By following the instructions on the blog post "Cloning Public Code: An Example" you should be able to get this working, but to help you a bit more here are some step by step instructions for manually cloning public code.

In this blogpost we'll be cloning TELNETD because for some reason sysgen_capture doesn't work for this component. TELNETD is located under the WINCE project tree "servers". I know the exact name of the WINCEPROJ by opening up the makefile in \PUBLIC\SERVERS\CESYSGEN and searching for WINCEPROJ. The correct sysgen_capture command for TELNETD would be:

sysgen_capture -p servers telnetd

The -p parameter indicates the WINCEPROJ, so in this case it's of course not "common", but "servers". Unfortunately for some reason this command doesn't output a sources.telnetd file (in fact it doesn't output any file!). No stress, let's just clone manually:

  1. Copy the TELNETD folder to your OS Design (\WINCE500\PBWorkspaces\<MyOSDesign>\TELNETD or \WINCE600\OSDesigns\<MyOSDesign>\<MyOSDesign>\TELNETD)
  2. Open the sources. file in the folder you just copied
  3. Set TARGETTYPE to DYNLINK
  4. Set RELEASETYPE to LOCAL
  5. Delete WINCETARGETFILE0=$(_RELEASELIBDIR)\$(TARGETDEFNAME).def
  6. Open the makefile. in <WINCEROOT>\PUBLIC\SERVERS\CESYSGEN and search for telnetd
  7. Copy the line @set TARGETLIBS... and @set DLLENTRY...
  8. Paste into your sources. file
  9. Change @set TARGETLIBS... in your sources. file to:
    TARGETLIBS=$(_PROJECTROOT)\cesysgen\sdk\lib\$(_CPUINDPATH)\ws2.lib \
               $(_PROJECTROOT)\cesysgen\sdk\lib\$(_CPUINDPATH)\coredll.lib \
               $(_PROJECTROOT)\cesysgen\sdk\lib\$(_CPUINDPATH)\ceosutil.lib  \
               $(_PROJECTROOT)\cesysgen\sdk\lib\$(_CPUINDPATH)\authhlp.lib
  10. Change @set DLLENTRY... in your sources. file to:
    DLLENTRY=DllEntry
  11. Add the include paths:
    _OEMINCPATH=$(_WINCEROOT)\public\common\oak\inc; $(_WINCEROOT)\public\common\sdk\inc; $(_WINCEROOT)\public\common\ddk\inc

    NOTE: DO NOT PUT SPACES BETWEEN THE PATHS! I know it is confusing because I do it above, but I have to to support line breaking (otherwise this page will look ugly...).

  12. And build...

Easy as that! Now that you have the TELNETD component successfully cloned you can continue following the instructions from step 7 in the blog post "Cloning Public Code: An Example" (of course replacing "netui" with "telnetd" in the text).

Here's the complete sources. file for reference (don't forget to delete the spaces in the _ISVINCPATH, _OEMINCPATH and INCLUDES macros! I need those spaces here to format the HTML nicely, but you will get compiler error "/I" requires an argument if you leave those spaces):

WINCEOEM=1
_OEMINCPATH=$(_WINCEROOT)\public\common\oak\inc; $(_WINCEROOT)\public\common\sdk\inc; $(_WINCEROOT)\public\common\ddk\inc

TARGETNAME=telnetd
TARGETTYPE=DYNLINK
RELEASETYPE=LOCAL

TARGETDEFNAME=$(TARGETNAME)
DEFFILE=$(TARGETNAME).def
CDEFINES=$(CDEFINES) -DwinCE
DLLENTRY=DllEntry

SOURCES=telnetd.cpp telndev.cpp consemu.cpp

TARGETLIBS=$(_PROJECTROOT)\cesysgen\sdk\lib\$(_CPUINDPATH)\ws2.lib \
           $(_PROJECTROOT)\cesysgen\sdk\lib\$(_CPUINDPATH)\coredll.lib \
           $(_PROJECTROOT)\cesysgen\sdk\lib\$(_CPUINDPATH)\ceosutil.lib  \
           $(_PROJECTROOT)\cesysgen\sdk\lib\$(_CPUINDPATH)\authhlp.lib

Cloning public code: An example

For some strange reason, people are still changing public code and doing build and sysgen's on their Windows CE tree (read this to learn why this is a bad thing). Changing code in the PUBLIC and PRIVATE trees might seem like a shortcut but actually it is everything but a shortcut. When you clone the code before changing it in place you will save yourself hours and hours of build time. A targeted build of a cloned driver takes seconds, a clean build and sysgen takes hours.

Cloning is not difficult at all, so there is really no reason to change PUBLIC or PRIVATE code. To prove that it is not difficult (once you know what you are doing) I will show you how to clone PUBLIC code in this blog post. Note that there is an article by Steve Maillet and Mike Hall in MSDN about cloning public code too. They split the clone into a "LIB" part and a "DLL" part. I don't really like that method; I just merge the sources file into one that creates the DLL in one go. Have a look at the "split" method here.

I chose to clone NETUI, since this component is responsible for a lot of dialog boxes that you may want to change to match your systems specifications.

I am cloning NETUI on a Windows CE 6.0 tree, but it works exactly the same on a Windows CE 5.0 tree (apart from the OSDesign folder which is called PBWorkspaces in CE 5.0).

Prerequisites: A sysgenned OSDesign with the "Network UI" component included.

Let's start!

  1. Copy the entire \WINCE600\PUBLIC\COMMON\OAK\DRIVERS\NETUI folder to your OSDesign, for instance \WINCE600\OSDesigns\MyOS\MyOS
  2. Open a build window (in Platform Builder / VS2005 click "Open Release Directory in Build Window" from the menu "Build"
  3. In the build window, type:
    cd..
    cd..
    cd netui
  4. Now type:
    sysgen_capture -p common netui

    This command will output a set of files in the current directory.

  5. Since we only want to build netui, you can delete:
    sources.btdrt
    sources.ceddk
    sources.iphlpapi
    sources.k.iphlpapi
    sources.ws2
    sources.ws2k
  6. Now intelligently merge sources. with sources.netui (we make the changes in the sources. file):
    • Make a backup of the sources. file (copy to sources.org) so you can always go back if needed
    • We are trying to build a DLL, so change TARGETTYPE=LIBRARY to TARGETTYPE=DYNLINK
    • We are building NETUI as a project in our workspace, so set the RELEASETYPE to LOCAL (RELEASETYPE=LOCAL)
    • We are not building a LIB anymore, so there's no need to preprocess the def file. Remove the following lines:
      WINCETARGETFILE0=$(_RELEASELIBDIR)\$(TARGETDEFNAME).def
      PREPROCESSDEFFILE=1
    • And add this line to tell the build system to use the local def file for the exports:

      DEFFILE=$(TARGETDEFNAME).def
    • We don't need the resource file later (because we are not creating a lib that has to be transformed into a dll later), so remove the COPYRES=1 line and the WINCETARGETFILES line pointing to the res.
    • OSDesign SubProjects get build last, so we don't need to copy SYNCHRONIZE_DRAIN=1 from sources.netui to our sources. file
    • Since we are now building a DLL, copy the DLLENTRY line from sources.netui to sources.
    • Now move the entire SOURCELIBS and TARGETLIBS from sources.netui to sources.
    • and delete any references to netui (netui.lib/netui.res) itself (because we are building that now)
    • Change the paths to the target libraries from using the PUBLIC sysgened libraries to the libraries sysgened to your workspace, so change $(_SYSGENSDKROOT)\ to $(_PROJECTROOT)\cesysgen\sdk\ and $(_SYSGENOAKROOT)\ to $(_PROJECTROOT)\cesysgen\oak\
    • You can also delete the #xref lines, they are remains of older days (CE 2.11 era).
    • Now try to build (by typing "build" in the build window you still have open)
    • oops! Doesn't build. It can't find the standard include files... Add the following to the top of the sources file:
      _ISVINCPATH=$(_WINCEROOT)\public\common\sdk\inc;
      _OEMINCPATH=$(_WINCEROOT)\public\common\ddk\inc; $(_WINCEROOT)\public\common\oak\inc; $(_WINCEROOT)\public\common\sdk\inc;

      NOTE: DO NOT PUT SPACES BETWEEN THE PATHS! I know it is confusing because I do it above, but I have to to support line breaking (otherwise this page will look ugly...).

    • And since this project is building OEM code (a kernel component) set WINCEOEM=1 to indicate we want to use the _OEMINCPATH (so if you really want to you can delete the _ISVINCPATH since we don't use that one).
    • Try to build again:
      BUILD: [01:0000000048:ERRORE] \WINCE600\OSDesigns\MyOS\MyOS\NETUI\.\btmgmtui.cpp(39) : fatal error C1083: Cannot open include file: '../bluetooth/sample/btenum/btenum.hxx': No such file or directory

      So, one of the sources files is trying to include a header on a relative path. Since NETUI came from \WINCE600\PUBLIC\COMMON\OAK\DRIVERS\NETUI this path must be \WINCE600\PUBLIC\COMMON\OAK\DRIVERS\BLUETOOTH

      Now there are 3 ways to solving this: Either add the \WINCE600\PUBLIC\COMMON\OAK\DRIVERS\NETUI folder to the include path (add INCLUDES=$(INCLUDES);\WINCE600\PUBLIC\COMMON\OAK\DRIVERS\NETUI) so that the header file can be found off the relative path, or change the source file including the header to use a full path to the header file, or copy the btenum.hxx file into the NETUI folder and change the source file including the header to use the local header file. I think the last option is the cleanest, so let's copy \WINCE600\PUBLIC\COMMON\OAK\DRIVERS\BLUETOOTH\SAMPLE\BTENUM\btenum.hxx to \WINCE600\OSDesigns\MyOS\MyOS\NETUI\btenum.hxx and change btmgmtui.cpp to #include "btenum.hxx"

    • Build again: 0 Warnings,  0 Errors. Whuuhooo!
    • Now there is one final thing we have to add to the NETUI sources. file. We have to tell the build system we want to copy the final binary to the _FLATRELEASEDIR so our netui.dll will overwrite the default one from the PUBLIC\COMMON folder. Add WINCEREL=1 to the top of the sources. file.
  7. Now add the NETUI project to your workspace. In the Platform Builder VS IDE click "Add Existing Subproject..." from the "Project" menu. Browse to the \WINCE600\OSDesigns\MyOS\MyOS\NETUI folder, select "Sources/Dirs Files" from the "Files of type" dropdown list, select the sources. file, and click "Open"
  8. In the Solution Explorer window you can now find your NETUI component under the "SubProjects" node. Right click NETUI and click "Rebuild" to see if you can build the project from the IDE. It should all build fine.
  9. If all builds fine, you can delete the sources.netui and the sources.org files since you no longer need them now.
  10. The "Insert existing project" action created a couple of files for you. One of those files is a bib file. BIB files are used to indicate which files need to be included in the image. Since we cloned NETUI, but did not remove it from the OSDesign features, we now have 2 references to NETUI in the combined BIB files (one is in COMMON.BIB and the other in our newly generated NETUI.BIB). We don't need an extra reference in the BIB files, all we want is overwrite the default NETUI.DLL in the _FLATRELEASEDIR, so you can remove this reference from the newly generated NETUI.bib.

Now you can change whatever you need to change in NETUI without worrying about messing up the PUBLIC portion of the WINCE tree or having to do a "Clean Build and Sysgen".

If you have followed all the steps above your final NETUI sources. file should look like this (except the spaces in the _ISVINCPATH, _OEMINCPATH and INCLUDES macros!):

_ISVINCPATH=$(_WINCEROOT)\public\common\sdk\inc;
_OEMINCPATH=$(_WINCEROOT)\public\common\ddk\inc; $(_WINCEROOT)\public\common\oak\inc; $(_WINCEROOT)\public\common\sdk\inc;

WINCEOEM=1
WINCEREL=1

TARGETNAME=netui
TARGETTYPE=DYNLINK
RELEASETYPE=LOCAL

TARGETDEFNAME=$(TARGETNAME)
DEFFILE=$(TARGETDEFNAME).def

DLLENTRY=_DllEntryCRTStartup

CONDITIONAL_INCLUDES=prshtp.h

SOURCELIBS=

TARGETLIBS=\
    $(_PUBLICROOT)\common\oak\lib\$(_CPUINDPATH)\btenum.lib \
    $(_PROJECTROOT)\cesysgen\sdk\lib\$(_CPUINDPATH)\iphlpapi.lib \
    $(_PROJECTROOT)\cesysgen\oak\lib\$(_CPUINDPATH)\btdrt.lib \
    $(_PROJECTROOT)\cesysgen\sdk\lib\$(_CPUINDPATH)\ws2.lib \
    $(_PROJECTROOT)\cesysgen\oak\lib\$(_CPUINDPATH)\ceddk.lib \
    $(_PROJECTROOT)\cesysgen\sdk\lib\$(_CPUINDPATH)\coredll.lib

SOURCES= \
    netui.c \
    getip.c \
    ipaddr.c \
    getuser.c \
    linecnfg.c \
    wnet.c \
    netcard.c \
    certui.cpp  \
    showcert.cpp \
    eaptlscfg.cpp \
    network.c \
    transdlg.c \
    reg.c \
    util.c \
    wzcui.c \
    wzcprops.c \
    btmgmtui.cpp \
    WzcQuickCfgUi.c \
    IpQuickCfgUi.c \
    QuickConfigUi.c \
    WzcLogging.c \
    WzcPopup.c \
    netui.rc  \
    wnet_wrapper.cpp \
    netui_wrapper.cpp \
    getuser_wrapper.cpp \
    gwes_wrapper.cpp \
    getip_wrapper.cpp \
    linecnfg_wrapper.cpp \
    transdlg_wrapper.cpp \
    network_wrapper.cpp \
    netcard_wrapper.cpp

FILE_VIEW_PARAMETER_FOLDER= \
    NETUI.bib \
    NETUI.reg \
    NETUI.dat \
    NETUI.db \
    ProjSysgen.bat \

FILE_VIEW_ROOT_FOLDER= \
    prelink.bat \
    postlink.bat \

PRELINK_PASS_CMD=prelink.bat
POSTLINK_PASS_CMD=postlink.bat

Filtering dat files

If you read this blog or the CE newsgroups you should by now know you should never change any files in the PUBLIC or PRIVATE folders of your WINCE installation tree. So what if you want to change a setting in common.reg (which is located in the PUBLIC folder)? Well, add the same entry to your platform.reg (in your PLATFORM\BSP folder) and set it to whatever you like. So, what if you want to delete a setting from common.reg? Again, add the same entry to your platform.reg but precede the key name with a "-". This works because platform.reg is merged into reginit.ini after common.reg, so any duplicate entries or deletion commands (the "-") will override the settings in common.reg.

So, what about dat files? Unfortunately, deleting dat entries with the "-" tag is not supported. Dat files are responsible for the initial copy of files and creation of folders during boot. For instance, dat files are used to copy shortcuts from the \Windows folder to the desktop of your CE device. Now what if you don't want to have icons on your desktop? The only way that seems possible is to actually change the public dat files in place, but you know you should never change any files in the PUBLIC tree! We just have to come up with a different solution...

The solution in this case is to filter the dat files and remove any unwanted lines before creating the final image but after the sysgen phase and without touching the original files in PUBLIC. Windows CE calls out to a number of batch files during the makeimg process to let you write your own scripts to affect the image at different points during the image building process. One of those batch files is "PostFmergeObj.bat" which, as the name suggests, is called just after fmerge merged the "Obj" files (which are in fact "Dat" files... confused already? ;o) into your FLATRELEASEDIR.

By using a bit of scripting magic we can use this batch file to filter out unwanted lines from the final merged InitObj.dat file:

Update:Line 18 is required to get this to work in WEC7/WEC2013

  1. REM   This batch file filters the DAT files
  2. REM   CE merges all DAT files into initobj.tmp
  3. REM   and then transforms initobj.tmp into a
  4. REM   UNICODE version initobj.dat.
  5. REM   Just before the conversion to unicode
  6. REM   the build system calls PostFmergeObj.bat
  7. REM   (this file). We filter out all the
  8. REM   strings defined in PostFmergeObj.txt
  9. REM   from initobj.tmp
  10.  
  11. @echo off
  12. echo PostFmergeObj.bat entry.
  13. pushd %_FLATRELEASEDIR%
  14. echo Deleting root:- entries from initobj.tmp
  15. del initobj.org
  16. ren initobj.tmp initobj.org
  17. findstr /i /v /g:PostFmergeObj.txt initobj.org > initobj.tmp
  18. txt2ucde initobj.tmp initobj.dat
  19. popd
  20. echo PostFmergeObj.bat exit.
  21. @echo on

The core of the script is from line 15 onwards. In line 15 we delete any previous initobj.org file this batch file may have left behind. Then, in line 16, we rename initobj.tmp (all dat files are merged into this file by fmerge) to initobj.org and in line 17 we call the dos utility Findstr:

>findstr /?
Searches for strings in files.

FINDSTR [/B] [/E] [/L] [/R] [/S] [/I] [/X] [/V] [/N] [/M] [/O] [/P] [/F:file]
        [/C:string] [/G:file] [/D:dir list] [/A:color attributes] [/OFF[LINE]]
        strings [[drive:][path]filename[ ...]]

  /B         Matches pattern if at the beginning of a line.
  /E         Matches pattern if at the end of a line.
  /L         Uses search strings literally.
  /R         Uses search strings as regular expressions.
  /S         Searches for matching files in the current directory and all
             subdirectories.
  /I         Specifies that the search is not to be case-sensitive.
  /X         Prints lines that match exactly.
  /V         Prints only lines that do not contain a match.
  /N         Prints the line number before each line that matches.
  /M         Prints only the filename if a file contains a match.
  /O         Prints character offset before each matching line.
  /P         Skip files with non-printable characters.
  /OFF[LINE] Do not skip files with offline attribute set.
  /A:attr    Specifies color attribute with two hex digits. See "color /?"
  /F:file    Reads file list from the specified file(/ stands for console).
  /C:string  Uses specified string as a literal search string.
  /G:file    Gets search strings from the specified file(/ stands for console).
  /D:dir     Search a semicolon delimited list of directories
  strings    Text to be searched for.
  [drive:][path]filename
             Specifies a file or files to search.

Use spaces to separate multiple search strings unless the argument is prefixed
with /C.  For example, 'FINDSTR "hello there" x.y' searches for "hello" or
"there" in file x.y.  'FINDSTR /C:"hello there" x.y' searches for
"hello there" in file x.y.

Regular expression quick reference:
  .        Wildcard: any character
  *        Repeat: zero or more occurances of previous character or class
  ^        Line position: beginning of line
  $        Line position: end of line
  [class]  Character class: any one character in set
  [^class] Inverse class: any one character not in set
  [x-y]    Range: any characters within the specified range
  \x       Escape: literal use of metacharacter x
  \<xyz    Word position: beginning of word
  xyz\>    Word position: end of word

For full information on FINDSTR regular expressions refer to the online Command
Reference.

By calling findstr with options /I and /V we effectively filter out the lines we specify in PostFmergeObj.txt and we pipe the output of findstr into InitObj.tmp. After this batch file returns the build system will call the "Text to Unicode" tool (Txt2ucde.exe) that converts any ASCII text strings in Initobj.tmp to Unicode text strings and creates the file Initobj.dat which then contains the Unicode conversion of InitObj.tmp (see http://msdn.microsoft.com/en-us/library/ms930234.aspx).

Note that you can also use regular expressions to find strings with findstr. Using this you have a very powerful tool to filter whatever file you want filtered and of course this trick doesn't only work on dat files, it works on any ascii text file (like bib, reg, etc).

All you have to do for all this to start working in your build is create PostFmergeObj.bat in your PLATFORM\BSP\FILES folder and copy'n'paste the above script. The Windows CE build system will automatically search for this batch file and if it finds it execute it just after it has merged the various configuration files. Don't forget to create a "PostFmergeObj.txt" file with the lines you want to delete from the final InitObj.dat file in the same folder as the batch file, like this:

root:-Directory("\Windows"):-Directory("www")
Directory("\Windows\www"):-Directory("wwwpub")
root:-Directory("Program Files")
root:-Directory("My Documents")
root:-File("Control Panel.lnk", "\Windows\control.lnk")
Directory("\Windows"):-Directory("Desktop")
Directory("\Windows"):-Directory("Programs")
Directory("\Windows"):-Directory("Recent")
Directory("\Program Files"):-File("Command Prompt.lnk","\Windows\cmd.lnk")
Directory("\Windows\Programs"):-File("Windows Explorer.lnk", "\Windows\explore.lnk")
Directory("\Windows\Programs"):-File("Command Prompt.lnk","\Windows\cmd.lnk")
Directory("\Program Files"):-File("Command Prompt.lnk","\Windows\cmd.lnk")

When you now perform a "make image" this batch file should automatically execute and its output (the "echo" commands in the batch file) should appear in the build output window.

.NET Micro Framework v3.0 SDK Beta

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:

Specification overview
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

  1. Open a build release window
  2. Type "cd %_targetplatroot%"
  3. Type "cd src"
  4. Type "cd drivers"
  5. Type "md sdbus2"
  6. Type "cd sdbus2"
  7. Type "sysgen_capture -p common sdbus"
  8. Now copy the files from <WINCEROOT>\PUBLIC\COMMON\OAK\DRIVER\SDCARD\SDBUS into <WINCEROOT>\PLATFORM\<YourBSP>\SRC\DRIVERS\SDBUS2
  9. And merge sources.sdbus and sources so you end up with this sources file:
  10. SYNCHRONIZE_BLOCK=1

    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.

  11. 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.
  12. And add the SDBUS2 folder to the dirs file in the DRIVERS folder.
  13. Don't forget to change any BSP component that links to $(_COMMONOAKROOT)\lib\$(_CPUINDPATH)\sdbus.lib to use the cloned SDBUS library, located at $(_TARGETPLATROOT)\lib\$(_CPUINDPATH)\sdbus.lib

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:

; SDHC Memory Storage class driver
[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 8 (CMD8)
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!

How to ask questions on the Microsoft Forums

This page is also available in Italian. Want to translate into your language? Let me know!

There are certain rules when you use a community driven forum to get answers to your questions. The Microsoft forums that deal with Platform Builder and Windows CE development are not actively monitored by Microsoft. The people answering your questions are your peers; volunteers who spend their time researching your problem because they find it interesting and want to learn more.

The people that post most answers are in many cases MVPs, Most Valuable Professionals, a status awarded by Microsoft to people who help out the community by running user groups, answering questions in forums, etc.

It is important to note that nobody is being paid to answer questions. They're all volunteers.

Now that you know this, you also know that there is no guarantee to get an answer. The most common reasons for not getting an answer are:

  • Your question has been answered in the forum in the past
  • Search before you ask!

  • You didn't supply enough information
  • "I call this function and it doesn't work, please help" is useless.

  • You keep on posting the same question over and over
  • If nobody answered your question after a couple of days it is because you didn't read this blog post on how to ask questions or simply because nobody knows an answer. If you want to "reactivate" your question, post a reply to your own question with something like "Anybody? Please?" and supply any other relevant information you may have gathered over the past few days. Do not start another thread for the same question. It is annoying and will result in people ignoring you.

  • You demand a quick answer
  • Demanding things from people you do not pay any money is generally counterproductive.

  • You're asking your question in the wrong forum
  • Before asking a question make sure you read at least some other questions and answers in the forum so you know this is the right forum. The forum title usually helps to determine this as well... ;)

Note that the above says nothing about "stupid" questions. That is because stupid questions do not exist! Everybody on the forums started with Windows CE/Embedded Compact at some point, and everybody struggled with the (sometimes) steep learning curve in the beginning. We know where you are coming from so don't be shy and ask, but before you do, take note of the following "rules" that will increase your chances in getting a useful answer:

  • Read MSDN Library
  • This sounds logical, but you'd be surprised how many questions are asked that can be easily found in MSDN. Click here for all the Windows Embedded documentation and use the search box in the top left hand corner to search. When you use search, make sure you check if the description you see is for "desktop" Windows, or for Windows Embedded. As you know, Windows CE/Embedded Compact uses a subset of the big Win32 API and some API parameters have different meaning in CE/WEC, so be careful there! That said, sometimes the big Win32 API description lists more information that also applies to and is still useful for CE/WEC. First thing to do when you encounter a problem with an API is to open the description of that API in MSDN, check all the parameters and read the remarks section. The remarks section has useful information about error conditions and special requisites that may be needed for the API. If you encounter a problem in the documentation, or missing information or something else wrong with the documentation make sure to rate the topic and/or add the missing information using the "Community Content add" link. The people at Microsoft responsible for the documentation really read this feedback and will update the documentation where necessary. Help make the documentation better!

  • Before asking a question, search the forums for an answer
  • If you can't find an answer in the forums you may also try to search the newsgroups archives (they were used before the forums and contain years and years of information about Windows CE):
    Use Google Group Search to search the newsgroups. Type some keywords in the "with all of the words" box, then in the "Return only messages from the group at this location" box type *windowsce* to search all newsgroups related to Windows CE. I also usually set the form to "Return 100 messages" and "Sort by Date" so I get the latest answers on the top of the list.

  • Subscribe to blogs
  • Most MVPs and some people within the Microsoft Product Team have blogs. Blog posts usually deal with a FAQoaF (a Frequently Asked Question on a Forum ;o), like the "What to build when" post on this blog. Some of the blogs that I subscribe to are the Windows CE Base Team Blog, Mike Hall's Windows Embedded Blog, the Windows Mobile Team Blog and of course the GuruCE Blog.

If your search did not return a useful answer you can post a question to the forum, but before you do: try a debug build, get KITL going and analyse the debug messages. If you can't build a debug kernel or get KITL going it will be difficult to get to the root of the problem, but not always. If you can't get KITL or a debug build going list that in your question!

Information that should be in your question:

  • OS version / hardware / board / kernel / updates
  • List the OS version, what hardware, what processor, what board, what BSP, debug or retail kernel, KITL yes/no, and what updates (QFEs) you installed

  • Specific Component
  • If you have problems with an existing driver or a specific component; tell us! Saying "I've got a problem with the touch driver" is useless, because there is no such thing as the touch driver. If you made the driver; tell us. If you cloned a driver, tell us which driver you cloned (including the original path you cloned from). If you are having problems with a standard driver, tell us exactly which one including the complete path. Example: "I've got problems with the MainstoneIII touch driver located in C:\WINCE600\PLATFORM\MAINSTONEIII\SRC\DRIVERS\TOUCH"

  • Big picture
  • Explain what you want to accomplish, not how you want to accomplish it. There may be better ways to get where you want. Describe the bigger picture.

  • What did you try
  • List the things you tried, the tests you performed and why it didn't work. If people ask you to perform another test: do it! Don't expect an answer if you are unwilling to follow advice that may lead to the solution of your problem. Also, if your search found a solution to your problem but somehow it didn't work, list that too.

  • Detailed error messages
  • If you got an error, list it. If an API returns an error, get the error number by calling GetLastError() and list it.

  • Detailed debug messages
  • Post the debug message lines that you think are relevant to the problem. Do not post 6000 lines of debug log because nobody will want to read through all of that.

  • Be polite
  • Don't demand an answer. Remember nobody is being paid to answer your questions. If you want paid support, buy support from Microsoft or one of the Embedded Partners, like GuruCE. Same goes for people answering questions; be polite, remember your own struggles when you started with CE.

  • Proof read / Spell check
  • We understand English is not the language the entire world speaks fluently; it's not my native language either. Spelling mistakes are common and not a problem at all, but before you post; at least read back what you wrote and make sure it is understandable. Don't just check for funny sentences and spelling mistakes, make sure there is enough information in the message for other people to understand your problem. The quality of the answer can only be as good as the quality of the question!

  • MSN/SMS/Text Generation
  • Remember you are not paying per-byte on the forums so please refrain from trying to shorten your messages. Do not use "ur" instead of "you're" or "2" instead of "to". It makes the message unreadable/annoying. R3m3mb3r typing l1k3 th1s do3s n0t m@k3 u 3733T, 1t 1ly m@k3$ u l00k st00p1d!

If you follow these rules (that are valid for any community driven forum) then there are no stupid questions and you will most certainly get an answer from one of the many volunteers answering questions in the forums.

Here's a template you can use to ask questions in the Windows Embedded Compact forums:

OS........: [CE 4.2 / CE 5.0 / CE 6.0 R2 / WEC7] [with updates until February 2012]
Hardware..: [Custom board / Device Solutions Topaz / etc]
Processor.: [iMX25 / PXA320 / etc]
BSP.......: [Custom BSP based on Mainstone III / GuruCE Topaz BSP / etc]
Kernel....: [Debug / Retail / Checked] [KITL enabled/disabled]

I am trying to [explain what you are trying to accomplish]

I am using [list the related component/driver including the full path]

I've tried to [explain what you have tried so far, how you tested, etc]

I searched the web and the forums and found [this/nothing]:

[url to something relevant]

I've tried to implement that but it didn't solve my problem because [explain why not]

Here's the code I use:

[show a code snippet if relevant]

The call returns [whatever the call returns] and GetLastError() returns [whatever error it returns]

The debug output window shows this:

[list a couple of lines around the debug log lines that you think are relevant]

I would much appreciate any pointers you can give me.

Thanks!

[Your Name]

Two final requests: When someone answers your question be sure to mark that reply as the answer. It is just a token of your appreciation and recognition for that person. Also: Return the favor!

Once you find a solution to your problem, either by yourself or because of a tip from somebody on the forums, please spend 5 minutes to write it down and post it as a reply to your original question. Your solution may save somebody a lot of time and frustration in the future.

Why not become part of the community? Don't be afraid to answer questions if you think you know the answer!

CE 6.0 / R2 BSP template

The Windows CE Base Team just posted a CE 6.0 template for a BSP on their blog:

http://blogs.msdn.com/ce_base/archive/2008/05/30/bsp-template-now-available-for-ce-6-0-ce6r2.aspx

The template contains help and instructions on how to use the template as a base for your own BSP:

The BSP Template is designed to help developers who are new to Windows CE BSPs. It is also designed to assist developers who want more information on a specific CE BSP technology.

It contains information on KITL, bootloader, drivers and the OAL. If you are developing a BSP, porting a BSP from 5.0 to 6.0, developing drivers or are just interested in BSP development for CE 6.0 then download it and learn!

Download QFE's

[UPDATE: the links in this blog post do not work anymore. For updated links click here]

How do you find the list of updates available for CE 4.2, 5.0 or 6.0?

The official way is to go to http://msdn.microsoft.com/en-us/embedded/aa731256.aspx and yes, it does show the QFE's for the various versions but wait...

...there's more!

Like the USB 6.0 webcam source, or the various help updates, or eVC 4.0 SP4, or the run-time assesment tool, or the mainstone BSP update, or ...

All things you may like to download too but that you won't find on the "official" page for downloading CE updates. If you'd like the complete list try these links:

CE 4.2

CE 5.0

CE 6.0

They show you 50 downloads per page sorted from new to old. Handy!

PS. Don't forget to download the QFEInstaller so you don't have to click the QFE installation wizard a million times: QFEInstaller

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:

@echo off
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
del 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!

http://urana.info/mobile/wince/itaskmgr/index.html

Offline installation of the CE 6.0 R2 update

The Microsoft installer for the CE 6.0 R2 update is a webinstaller. This means there is no way to download once - install often. Since the complete R2 update is over 1 GB of data it would be nice to be able to download the package to a folder from which you can install the R2 update offline. This is especially handy if you need to install the R2 update on multiple machines.

Another reason would be if you, like me, get errors during installation. When I tried to install the R2 update I got error messages like:

"Error 1335. The cabinet file 'MSI4E0.tmp' required for this installation is corrupt and cannot be used. This could indicate a network error, an error reading from the CD-ROM, or a problem with this package.".

So I dissected the MSI log files and was able to determine some downloaded cabinets were in fact corrupted. The corruption only seemed to occur when downloading using the Microsoft Installer package. When I manually downloaded the cabinets there was no corruption. By looking at the log files I could get a list of all required cabinet files. Since there are quite a few of those cabinets, and I figured this could be handy for more people, I wrote a tool that downloads the entire package from the Microsoft download server into a folder. Once the download is complete (1.1 GB) run the installer (Windows Embedded CE 6.0 R2.msi) to install the R2 update. You don't need to be connected to the internet while installing.

Download the tool (including source): DownloadCE6R2.zip

What to build when...

[An updated version of this post for WEC2013 can be found here]

A question that keeps coming back on the newsgroups is "I changed some code, but it does not end up in my image", or "I changed some registry values in platform.reg, but if I look at the device registry, it's not there!".

The source of these problems is build-related. You've got to understand the build system in order to know exactly what to do. This blog post aims to give you a clear handle on "What to build when"!

The first and most important thing to do is to delete two options from the Platform Builder Build menu: Build and Sysgen and Rebuild and Clean Sysgen. These commands will build the entire tree (so including any source in PUBLIC and PRIVATE). For us normal developers these commands do not make any sense. If you're not in the CE development team working at Microsoft you simply don't have all the source code. Rebuilding the entire tree may work, but it will override any installed QFE (QFE's contain updated binaries and sometimes, but not always, updated source code). After rebuilding the entire tree you will sooner or later encounter strange errors that are either very hard to fix, or just impossible to fix. There is no way to revert back to a clean tree once you've done a (Re)Build and (Clean) Sysgen. The only way is to completely remove Windows CE and reinstall. Don't forget to reinstall all QFE's after that as well (download the QFEInstaller tool to help with that).

Now you know why you often see me shouting NEVER EVER DO A BUILD AND SYSGEN! in the newsgroups...

UPDATE: The instructions for removing the bad build commands from the menu are for Windows CE 5.0/6.0. For instructions on Windows Embedded Compact 7 read this. Note that the below "What to build when" instructions are STILL VALID for WEC7 AND WEC2013!

The original menu
The original Advanced Build Commands menu

Step 1.
Customize toolbar
Right click on the toolbar and click Customize...


Step 2.
Delete Build and Sysgen
Click on menu Build, submenu Advanced Build Commands, then right click on Build and Sysgen and click Delete


Step 3.
Delete Rebuild and Clean Sysgen
Do the same for Rebuild and Clean Sysgen


Step 4.
The original menu
Close the Customize window. The Advanced Build Commands menu should now have only 4 options: [Sysgen], [Clean Sysgen], [Build Current BSP and Subprojects] and [Rebuild Current BSP and Subprojects].



If you are still using Platform Builder for Windows CE 5.0 the instructions stay the same except the Build menu is Build OS and there's no submenu (everything is under the Build OS menu).

I know that some developers working with CE change code in the PUBLIC and PRIVATE trees. If you do that you need to do a build and sysgen to include your changes in your kernels BUT: You will end up with a corrupted CE installation. If you need to change PUBLIC or PRIVATE code you have to clone the code. Cloning code is in most cases not much more than a simple copy. Copy the sources you want to change to a folder in your BSP, change the sources file so that it builds a DLL instead of a lib and voila, you're done. I know I make it sound easier than it is, but taking a shortcut and modifying code in the PUBLIC or PRIVATE trees will prove to be a long way around in the long run.

Phew! Now that we got that out of the way let's see what build command we've got to use in what situation:

  • Create a new OS Design (or add a new build configuration to an existing OS Design): Sysgen (Build Solution)
  • Since a new OS Design doesn't have anything in its build configuration's output folders (same with a new build configuration) you'll have to sysgen the entire solution (for that build configuration). The longest process, but luckily you don't have to do this many times (see below).

  • Change Platform Settings: Make image
  • Platform Settings
    If you change any Platform Settings (like IMGNOKITL, IMGNODEBUGGER, IMGPROFILER) all you have to do is a Make Image.

  • Change driver source code in your BSP: Build the driver and Make Image
  • If you change driver source code, all you have to do is just build the driver (WINCEREL must be set to 1 but it is set by default so unless you changed it there's no need to worry) and do a makeimg. If you only want to debug the driver you can also add the DLL to the Release Directory Modules list (menu Tools) and just restart the device (or reload the device driver on the device) without having to do a makeimg and download to device. Building just the driver is a simple right-click on the driver and Build in the IDE or "build" in the driver's folder on the command line.

  • Change multiple source code files in your BSP: Build the BSP and Make Image
  • The safe option, this way you can't forget to rebuild anything. Building the BSP is a simple right-click on the PLATFORM\BSP folder and Build in the IDE or "build" in the BSP's root folder on the command line.

  • Change platform.reg, bib, dat or db files in your BSP: Sysgen BSP, Copy Files to Release Directory, Build All Subprojects and Make Image
  • A lot of steps, but this will still not take longer than a couple of minutes. If you change any of the platform.* files we need to re-filter (Sysgen) those files and make sure the filtered files are copied into the FLATRELEASEDIR (Copy Files to Release Directory). That last action did however clear the project binaries from the FLATRELEASEDIR so we need to make sure those binaries and settings are getting copied into the FLATRELEASEDIR again (Build All Subprojects) and finally we are ready to Make Image. Now your registry changes will be in the image (check reginit.ini to make sure, last entry wins).

  • Change some source files and platform.reg, bib, dat or db files in your BSP: Build and Sysgen the BSP, Copy Files to Release Directory, Build All Subprojects and Make Image
  • Only difference with previous situation is that you now have to build the BSP to include the source code changes.

    Please note that "Build and Sysgen the BSP" is not the evil "Build and Sysgen" command. The evil command is only in the Build menu (and should not be anymore if you followed the instructions above). The "Build and Sysgen BSP" command can be executed by right clicking your BSP root node in the Solution Explorer and choosing "Build and Sysgen (cebuild -qbsp)". Notice the -q in that command? That shows you it's a good command...

  • Change the workspace configuration (add or delete a component): Sysgen the entire workspace (Build solution)
  • For most components a simple Sysgen is enough. For some components (like when changing from RAM based registry to Hive based Registry) a Clean Sysgen is needed. This action takes the longest (anywhere from 5 minutes for a small workspace configuration on a very fast machine to a couple of hours for a really big configuration and a very slow machine). A Sysgen is a right-click on the workspace, Advanced Build Commands->Sysgen in the IDE or "blddemo -q" on the command line.

  • After installing one or multiple QFEs: Clean Sysgen the entire workspace (Rebuild solution)
  • To make sure all components are re-linked with the (possibly updated) libraries a Clean Sysgen is needed. This action takes the longest (anywhere from 5 minutes for a small workspace configuration on a very fast machine to a couple of hours for a really big configuration and a very slow machine). A Clean Sysgen can be performed by choosing Rebuild Solution from the build menu, or choosing Advanced Build Commands->Clean Sysgen in the IDE or "blddemo clean -q" on the command line.

Sometimes it's easier to build from the command line. If you are unsure what command to type you can always perform the action in the IDE first and watch the 3rd line in the build output window starting with "Starting Build:". Behind the colon is the exact command line for that action, eg Sysgen on the BSP: "Starting Build: SysgenPlatform %_TARGETPLATROOT% preproc&&SysgenPlatform %_TARGETPLATROOT% postproc", so on the command line you would type "SysgenPlatform %_TARGETPLATROOT% preproc" followed by enter and the 2nd command "SysgenPlatform %_TARGETPLATROOT% postproc" followed by enter.

If you use the commandline, make sure you never forget "-q" when running "blddemo" as "blddemo" without "-q" is a Build and Sysgen!

I hope this blog post will help you speed up your builds and lower your frustration with the build system!

Good luck!

Air New Zealand Crash!

Last Sunday I got the biggest scare I have ever had on a plane. I am not scared of flying, in fact I love flying, but this time I got really, really, really scared...

I was watching a movie on the in-flight entertainment system. It was the middle of the night, half the plane was asleep when all of a sudden the stewardess taps me on the shoulder and says:

"Sir, we are shutting down the entertainment system because we are crashing..."

At that moment my heart rate went through the roof, I immediately started looking around to see if there was turmoil in the plane, then looked at her and said "What? Are we crashing?!". Apparently I had misunderstood her, she must've said "it [the entertainment system] is crashing". The stewardess apologized for the bad choice of words and we had a good (& very relieved) laugh about it.

Of course all this would not have happened if the in-flight entertainment system had not crashed...

In retrospect I am pleased it crashed because it gave me some insight in the system behind the Air New Zealand in-flight entertainment system: It is running CE.

CE.NET 4.xI should've been excited about that and used an exclamation mark on that last sentence, but how can I be excited about a system that has to be rebooted every 6 hours? I can imagine an already nervous passenger would become very nervous when he realizes even something simple like the in-flight entertainment system crashes!

Besides that obvious "crashing" problem the control of the system is sluggish, sometimes even completely non-responsive. The graphics of the "Air Show", the application that shows where the plane is, is however very impressive and looks very smooth. The board running CE is definitely fast enough to support fast 3D graphics and streaming video so why is control so slow? And why the crash?

I think the problem is that the company that designed the in-flight entertainment system used (this is an educated guess) the Internet Explorer as a host for the "Entertainment" application. The crash is probably caused by a memory leak in the browser application. Bad design? I think so...

Windows CE is a real-time operating system that can run 24/7 without ever having to reboot the system. In fact, several customers have been running CE devices for several years without ever having to reboot their device. I'm just saying I would love to take a closer look at the Air New Zealand entertainment system and see whether my educated guess is close to the truth.

So... Rockwell Collins (or Air NZ): Give us a call. I'm sure we can help you create a much more robust and responsive system.

Here's a funny side effect of a "mid-air crash" of the Air NZ in-flight entertainment system: LA to Auckland in a little over 6 hours with a Boeing 747-400, now THAT'S impressive! (Normal flying time is around 12 hours, video is bad quality but it says 6 hours 13 minutes...)
CE Boot 2
More info:
http://www.rockwellcollins.com/news/page5495.html

Welcome!

The first entry of the GuruCE blog of course has to be a special one!

Therefore, we start this blog with a tool I developed in the past:

The QFE Installer

Ever had to reinstall Windows CE? Then you had to reinstall all the QFE's as well. Not a nice task, it's lengthy and you have to stay close to your computer because there are about 12 screens you have click through before it actually installs. There is unfortunately no way to install all QFE's without a user controlling the mouse... until now!
The QFE installer installs all the QFE's you downloaded in the exact right order, from oldest to newest, without the need for one mouse click. Just copy the QFEInstaller.exe in the folder containing all the Windows CE QFE's and run it. Source available for free, just drop us a line.

Download QFEInstaller

Keep an eye on this blog for future tips & tricks and more tools for the CE developer!

Pages

Subscribe to RSS - blogs