Microsoft Windows CE 3.0 Technical Articles  

Common Executable Format for eMbedded Visual C++ in Microsoft Windows CE 3.0

Important:
This is retired content. This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This content may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

Microsoft Corporation

June 2000

Summary:This article discusses Common Executable Format (CEF), a processor-neutral code format that enables the creation of portable applications across CPUs supported by Microsoft Windows CE. CEF enables Windows CE application developers to deliver products that support all the CPU architectures that run the Windows CE operating system. (17 printed pages)

Contents

Introduction
CEF for Microsoft eMbedded Visual C++
Advantages and Disadvantages of CEF
How CEF Works
The Device Translator
The Desktop Translator
CEF Language Requirements
Configuring a CEF Project
Limitations and Recommendations
Building and Linking a CEF Application
Debugging a CEF Application
Delivering a CEF Application
Distributing CEF Applications as Bare .exe, .dll, or .ocx File
CEF Translator Reference
MkCEFlib Reference
Requirements for the Native-Code DLL
Preparing to Run MkCEFlib
Running MkCEFlib
Actions Performed by MkCEFlib
Troubleshooting MkCEFlib
MkCEFlib Command Line
Conclusion

Introduction

Common Executable Format (CEF) is a processor-neutral code format that enables the creation of portable applications across CPUs supported by Microsoft Windows CE. Microsoft eMbedded Visual C++ can be configured to produce CEF code instead of a native machine language code (such as MIPS or x86 code). In eMbedded Visual C++, CEF Tools (compilers, linkers, and SDK) are made available to the developer the same way a specific CPU target (such as MIPS or ARM) is selected. When a developer compiles a CEF application, the compiler and linker does everything but generate machine-specific code. You still get a .dll or .exe, but the file contains intermediate language instructions instead of native machine code instructions. When the user installs a CEF application on a Windows CE device, a translator generates the corresponding native machine code for the device.

CEF enables Windows CE application developers to deliver products that support all the CPU architectures that run the Windows CE operating system. Because CEF is an intermediate language, processor vendors can easily add a new CPU family that runs CEF applications. They just port Windows CE to their process and write the CEF compiler.

CEF for Microsoft eMbedded Visual C++

CEF for Microsoft eMbedded Visual C++ builds applications that can be installed on any of the supported Windows CE processors (currently ARM, MIPS, PPC, SHx, and x86) for that device category (for example, Pocket PC).

Because CEF is an intermediate CPU-independent language, a CEF application can also be installed and run on any future CEF-supported processor for that device category. All that would be required is for the device operating system to include the CEF translator whenever a new processor is supported.

CEF-based applications run on a single platform (for example, Pocket PC), but on different processors. For example, a CEF executable file built for the Pocket PC will run on any Pocket PC device. It will not run on a Handheld PC. CEF support is available on the Pocket PC platform and any Windows CE platform created with Microsoft Windows CE Platform Builder 3.0 where CEF support has been enabled.

Advantages and Disadvantages of CEF

Deploying applications to multiple CPUs imposes a cost to developers who want to support a Windows CE platform. Although standardized APIs and tools are generally available, it takes resources to test, package, and distribute a product for multiple CPUs. Multiple CPUs also impose costs on users. To install applications, users also must know which CPU runs their Windows CE devices. If a customer has a new device, the available software may be limited. Users with devices supported by different CPUs may also find that moving or sharing software is complicated.

Advantages of CEF

  • CEF enables shrink-wrap software and Web-based programs (for example, Microsoft ActiveX controls) to support multiple processor architectures, including processors that were not available when the application was written.
  • CEF requires reduced support because users need not know what CPU is running on their device.
  • Users need only to download executable(s) in CEF if they are getting their application from the Web. Without CEF, they must download a .cab file with executable(s) of all the CPU variants for their device.
  • CEF requires no change to programming languages or run-time environments. You use eMbedded Visual C++ just as you would for a specific processor.

    Disadvantages of CEF

    • Most internal benchmarks show that CEF code runs 3 percent to 20 percent slower than code compiled for a specific processor. However, in real-world applications, this performance hit is not distinguishable because real-world code spends most of its time in the system.
    • In the internal benchmark tests, native code converted from CEF may be from 10 percent to 20 percent larger than code compiled and optimized for a specific processor. However, this penalty affects code only. Since most real-world applications are made up mainly of data and resources, the overall penalty to a full-blown application is much less than the benchmark figures.

      CEF delivers a single executable file for multiple CPUs. This feature can be useful whenever you must support multiple CPUs. For example, you can post a single executable file for Pocket PC devices on a Web site, which users can download for any Pocket PC device using any processor. CEF is not appropriate when you want an application optimized to run only on a particular processor. This applies particularly if you are going to put an application in ROM or otherwise design it for a particular processor.

      How CEF Works

      CEF provides processor compatibility for any application created to run on a particular device (for example, the Pocket PC or the Handheld PC, but not both). CEF does not provide for running an application on different devices/platforms.

      Building a CEF application is simply a matter of choosing the WCE CEF configuration for the build process. During compilation, this configuration invokes the clcef.exe compiler to generate code. When linking, it invokes the linkcef.exe linker. The final binary is output in the same manner and named in the same manner as processor-specific executables, but marked with a machine type of CEF within the binary.

      When a user installs the common executable on a CEF-enabled Windows CE device, the translator translates the common executable file to the native executable file. Translators are available for all Windows CE-supported processors. Two modes of translation are available with CEF: device-side translation or host (desktop)-side translation. The device-side translator generates a native executable from a CEF executable with the translator resident on the device ROM. The host-side or desktop (PC) translator generates a native executable with a translator resident on the desktop. The host-side translator is made available with embedded Visual C++.

      The Device Translator

      The device translator is specific to a particular processor and Windows CE device. The device version normally translates a CEF executable to the native code of that processor when the user installs the executable on the device. This occurs seamlessly, without any indication to the user other than a brief pause for translation. An operating system hook also catches any attempt to load and execute a CEF .exe, .dll, or .ocx file automatically and invokes the translator before running the file.

      The Desktop Translator

      The desktop translator is most useful during the development and debugging of CEF applications. The desktop translator supports debugging by translating .pdb information from CEF into native form so that the result can be debugged. After translation occurs, the native form of the application (with debug information) is downloaded to the target device. Now the application can be debugged remotely from the desktop with the debugger in eMbedded Visual C++.

      Desktop translators for every processor family are included with eMbedded Visual C++. These translators run on Microsoft Windows 2000, Microsoft Windows NT, or Windows 98 host computers running the Microsoft eMbedded Visual Tools.

      CEF Language Requirements

      One advantage of CEF is that you do not need to learn any new language or language constructs to create a CEF application. You can code in C++ and use the Windows CE APIs just as you would for any specific processor.

      Although you must use C++, CEF does support C code with the /TP /C /CEF build switches. The /TP switch is required to compile C code as C++. However, if you do use C code, it must meet C++ rules to provide valid input for a C++ compiler. Function definitions, type conversions, and other language elements must follow C++ rules. If you want to use code that currently does not meet C++ requirements, you must upgrade it. All changes for C++ rules are backward compatible; so, after you make changes, you can still build your code with an ANSI C compiler.

      • If you use Kernighan and Ritchie (K&R) C you will find that there are function definitions that do not work in C++. K&R C also has problems handling type conversions and function declarations as required by C++ rules. You will need to update your function declarations to the modern "prototype" form, in which both the function name and type are given in the argument list. In the code, the function calls must also be changed to match the declarations.
      • ANSI C more closely fulfills C++ requirements. Almost all ANSI C syntax is accepted by C++. Some typecasts, most commonly involving pointers, that C accepts implicitly must be made explicit for C++.
      • The basic Unicode wide-character data type wchar_t(the 16-bit counterpart to an 8-bit signed char) is defined as unsigned short in native eMbedded Visual C++ compilers, but is an intrinsic type in the eMbedded Visual C++ CEF compiler (according to recent changes in ANSI C). This occasionally requires an explicit wchar_tcast in places where an integer has been used.
      • You may need to place extern "C" { ... } bracketing around headers and sources that must export names with C linkage rules rather than the C++ decorated name rules. This is necessary only in the rare case that you are creating a DLL to which a native C-rules executable program or DLL will link by named imports. If your application is completely self-contained or it exports its functionality only through COM interfaces, then you can probably compile and link using C++ linkage.

        These are the most common syntax changes required to meet C++ rules. Refer to a comprehensive book on the C++ language for a more complete discussion of the differences between C and C++. The changes themselves are syntactic and result from the stricter compiler philosophy of C++. Changing your code to conform to the stricter rules will not change your algorithms nor prevent you from compiling your source code as ANSI C for other projects.

        Configuring a CEF Project

        To build a CEF executable file for an application, you must configure the Project for WCE CEF instead of a native processor. Use Set Active Configurationon the Buildmenu to select the active project configuration. You can also select the active configuration on the WCE Configurationtoolbar. Then, when you build your project, eMbedded Visual C++ compiles the source code as CEF-based .exe, .dll, or .ocx file.

        Project Settings for a CEF Build

        Choose Settingson the Projectmenu to configure project settings for a CEF project. Choose the C/C++tab of the Project Settingsdialog box to check the settings for each category listed in the Categorybox.

        Figure 1. Project Settings dialog box

        The following table lists the appropriate C/C++tab settings for a CEF project.

        Category Setting Notes
        General Optimization CEF optimization is less drastic than for other build configurations. This means that there will be less difference between size and speed in optimized code compared with non-optimized code.
          Common Options /CEF switch required/TP switch required for C code.
        C++ Language Representation method Best-Case Always* (only available option).
        Code Generation Processor DEFAULT (only available option).
          Use run-time library CE Run time* (only available option).
          Struct member alignment 8 Bytes* (required).
        Customize   No special settings.
        Listing Files   No special settings.
        Optimizations   Optimizations for CEF builds do not have nearly the effect as when building for a native compiler.
        Precompiled Headers   No precompiled headers available.
        Preprocessor   No special preprocessor settings.

        Limitations and Recommendations

        • Use Structured Exception Handling (SEH). This is recommended but not required. Jmpbuf (setjmp/longjmp) is deprecated, so SEH is better. A portable jmpbuf for a CEF application is set to the largest possible case of all the CPUs, which is very large. Mixing jmpbuf with native code is a poor practice. Do not use setjmp with new code.
        • The entry point to an image must be from one of the two groups of functions listed in the table. If there are functions from both the first group and the second, the function from the first group is used as the entry point. This is usually the case, because corelibc.lib normally provides a member from the first group.
          Group 1
          Group 2
          wWinMainCRTStartup
          Main
          WinMainCRTStartup
          Wmain
          mainCRTStartup
          WinMain
          _DllMainCRTStartup
          WWinMain
           
          DllMain
          • The xxxCRTStartupfunctions also make a call to our virtual pointer fix-up function. If the use overrides xxxCRTStartup, the functions will not get that functionality.
          • You cannot use inline native assembler code. Your C++ code can call native code, but inline assembly is unsupported.
          • You cannot use the rare APIs that are specific for a particular processor.
          • Avoid large, zero data segments (global or static data) in a program. The linker puts all the zero data in contiguous memory and optimizes it out of the .exe or .dll size, but it still takes space at translation time because the full program image is loaded as part of the translation process. Small amounts of static data are no problem, but it is best to allocate large arrays on the heap at startup.
          • Test CEF builds on at least two different CPUs before shipping a product. The Microsoft development team does its best to make code portable, but it is still important to assure that your code runs satisfactorily on more than one CPU. After you demonstrate that your code runs fine on a couple of CPUs, you can assume fairly safely that it can run on any CEF-enabled device target.
          • You may want to confirm that performance (speed and size) is satisfactory on Windows CE devices. Normally, performance of CEF applications decreases less than 20 percent from that of the native code, but the actual decrease depends on the application.

            Building and Linking a CEF Application

            Overview

            In the eMbedded Visual C++ IDE, building a CEF application is no different from building an application for any specific CPU. Compilation is performed by Clcef.exe and linking by Linkcef.exe. The CEF compiler and linker do support a few special options. To see all the options available for either Clcef.exe or Linkcef.exe, type clcef /? or linkcef /? at the command prompt.

            CEF Compiler Options

            The following switches are specific to the CEF compiler:

            Switch Description
            /cef Compile for Windows CE CEF (required)
            /noHRESULT Disable intrinsic HRESULT type
            /noWchar_t Disable wchar_tkeyword
            /noBool Disable boolkeyword
            /MP Compile using multiple processes

            The noWchar_tand the /noResultand /noBoolswitches may cause problems for linking to standard Windows CE import libraries. If the types disabled by these switches are used in function signatures, the linker will fail to match the functions when the types are disabled.

            CEF Linker Options

            The /MACHINE:CEFswitch is required for linking CEF files. The CEF argument is the only one supported for the /MACHINEswitch for Linkcef.exe. The CEF argument is not supported by Link.exe, which does not link CEF binaries.

            The /SUBSYSTEMswitch tells the operating system how to run an .exe file generated by a build. For a CEF build, specify /SUBSYSTEM:WINDOWSCE. The /SUBSYSTEM:WINDOWSCEoption is required for Linkcef.exe. This is also the only subsystem you can specify for Linkcef.exe.

            Use /WINDOWSCE:CONVERTfor linking CEF builds. The EMULATIONargument is used for building a desktop Windows CE application that runs under the emulator, and Linkcef.exe does not link binaries for emulation.

            Debugging a CEF Application

            Overview

            When you build a debug version of a CEF application, all debugging takes place on a native translation of the application. The linker builds a CEF PE (such as .exe, .dll, or .ocx) file and a .pdb file. The desktop translator converts the CEF PE and .pdb files to a native format. This enables the source code and the native executable to stay synchronized, so that the native version of the .pdb correctly references source line numbers while you debug the native version.

            Strategy

            The primary objective of CEF is to provide developers with a simple way to distribute their product for multiple CPUs with Windows CE. For most of your debugging, use the native executable for the CPU on your Windows CE device. The CEF code is optimized, and optimized code can be difficult to debug. You also lose a lot of information in the compilation of source code to CEF and in the translation to native code. Develop the product on an available CPU. Test the CEF build only after the code has been debugged in the native format for the CPU, and the project is near completion. CEF is for delivering a product, not for developing a product.

            We also recommend against transferring the debug version of a CEF build, particularly a debug static MFC build, to a device. A debug build requires several times more translation resources than a regular build. Transferring a debug version to the host may work if the device CPU has a lot of memory, but the design is not made for doing this.

            Methodology

            Automatic Binary Download

            For testing purposes, you can choose whether to automatically download an application to the attached device after building it. You can change the download options on the Downloadtab of the Optionsdialog box (choose Optionson the Toolsmenu).

            Figure 2. Options dialog box

            Select or clear the check boxes to always download the binary or dependencies to the target device after you compile the project.

            Manual Binary Download

            If you clear the Always download ...checkboxes on the Downloadtab of the Optionsdialog box, you can download the application manually after you compile it by choosing Update Remote Output Fileon the Tools/Buildmenu.

            Figure 3. Choosing Update Remote Output File(s)

            Host/Device-Side Translation

            You can also choose whether to translate the CEF executable to native format before downloading by selecting Always translate CEF executable to native format before downloadingon the Downloadtab of the Optionsdialog box. If you clear this option, the executable will be translated to native format when it is executed on the target device.

            Figure 4. Options dialog box

            Delivering a CEF Application

            Using a CAB File to Distribute CEF Applications

            If a CEF application is going to be installed on more than one computer (for example, passed around on a flash card), you should always use a CAB file to install the application. When the translator installs from an .exe, .dll, or .ocx file, it replaces the original file with the translated file. In contrast, when you use a CAB file, the Windows CE loader (Wceload.exe) first unpacks the CAB and stores the executable files. The loader then calls a Setup.dll unpacked from the CAB, and it in turn calls the CEF translator. The CEF files are still overwritten by the native executable files, but the CAB files are retained and can be used elsewhere.

            Distributing CEF Applications as Bare .exe, .dll, or .ocx File

            If a CEF application is to be installed only once (for example, an .ocx file or isolated binary downloaded and installed from a Web page), you may choose to use a bare .exe, .dll, or .ocx file. Because no CAB is involved, the file will simply be translated and overwritten the first time it is run. In order to use it on another device, the user will have to get a new copy from the Web page or other source.

            If you are using Platform Builder to define your own platform, you should configure Wceload.exe as part of your platform to provide CEF support.

            CEF Translator Reference

            The CEF translator can be invoked by running an executable (Ceft.exe) or by having the operating system automatically detect the CEF application when the application is first executed.

            On a custom-built platform configured with the Platform Builder product, Ceft.exe is available only when it is included in the platform configuration.

            Configuring CEF Translation During Host Download

            When you are working in eMbedded Visual C++, the IDE is initially configured to automatically translate the CEF file to the native executable file before it downloads the executable file to the native device. To turn this option on or off for testing and debugging, choose Optionson the Toolsmenu to display the Optionsdialog box. Then, on the Downloadtab, select or clear the Always translate CEF executable to native format before downloadingcheck box.

            Figure 5. Options dialog box

            If you clear this check box but leave the other two Download Optionscheck boxes selected, the IDE downloads the CEF file to the target device without translating it to the native executable. The CEF file will then be translated on the target device the first time that you run it.

            Translating a CEF Application While Debugging

            If the CEF executable file has not been translated when you begin a debugging session, the IDE prompts you to convert the file before beginning the session. Furthermore, during a debugging session, the debugger requires translation of any program not translated during the download, even if you manually translate it in the output directory or on the device. This is because the debugger requires translation of the debug information, and only the translator on the host computer supports translation of the debug information.

            CEFT Command Line

            On the desktop computer and on Windows CE devices that support the CEFT utility, you can use Ceft.exe to manually translate CEF executables. Ceft.exe on the desktop is stored in the Microsoft Embedded Tools\EVC\ osfolder \Bin folder (where osfolderis WCE300 or later). Use the following command line syntax for the CEFT utility.

            Desktop Syntax

            CEFT -cpu cefexecutable [[path]nativeexecutable]

            Windows CE Device Syntax

            CEFT cefexecutable [[path]nativeexecutable]

            The cpuis one of the CEF-supported operating systems. Currently, you can use ARM, MIPS, SH3, SH4, PPC, or x86. These can change as Microsoft supports additional Windows CE operating systems. The help displayed by typing CEFT /? lists the operating systems supported by the Ceft.exe. This argument is unavailable on a Windows CE device, where CEFT automatically calls the device-specific translator stored in ROM.

            The cefexecutableis a CEF executable file that was compiled in the IDE or by Clcef.exe on the command prompt.

            The nativeexecutablespecifies the output file, which is an executable for the designated operating system. If you do not specify an output file, then CEFT generates a name using cpu.cefexecutable.

            Performing Device-Side Translation on an ODO

            If you are testing a CEF application on an ODO, device-side translation of the CEF executable cannot take place when attempting to execute a CEF application in the release directory (specified by the _FLATRELEASEDIR environmental variable). Kernel-mode hooks for CEF applications do not affect applications run in the _FLATRELEASEDIR directory. In order to perform device side translation on an ODO, the executable must be transferred to the device itself.

            ODO refers to the Hitachi D9000 Handheld PC hardware development platform. This device supports microprocessors from multiple vendors.

            MkCEFlib Reference

            MkCEFlib prepares import libraries for CEF applications, which allow native code DLLs to be called by CEF applications or CEF DLLs. CEF uses a different binary format for its libraries to which native-code libraries must be converted to be used by a CEF application. MkCEFlib extracts the contents of native import libraries and compiles an equivalent CEF import library. You link this library to your CEF project to enable the compiled CEF application to use the native DLL.

            The CEF translator handles APIs exported by name. Although C++ decorated names vary slightly on different CPU architectures, the translator transforms the CEF form of the name to the appropriate decorated name for a particular CPU.

            Requirements for the Native-Code DLL

            The native-code DLL must provide a uniform API that exports the same functions on all supported CPUs. If a native-code DLL exports CPU-specific functions, a CEF application should never call them. We strongly recommend that you exclude any CPU-specific functions from the CEF import library.

            If your native-code DLL exports any functions by ordinal, you must be careful to use identical ordinals on all CPUs. There are different ways to set up ordinals, but you must be sure that they are the same on every CPU supported by your DLL. If a DLL is not standardized across CPUs, then CEF application cannot use it transparently on every CPU.

            Preparing to Run MkCEFlib

            Be sure that the native-code DLL is stable before you run MkCEFlib. MkCEFlib must do a compilation for every API function, which may require something on the order of 10 minutes for every 100 functions. Any time you change the export set of functions for a DLL, you must rerun MkCEFlib. If you are still developing, testing, or debugging a DLL, running MkCEFlib consumes time very likely better spent on those tasks. When you are ready to create the CEF import library for the DLL, complete the following steps before you run MkCEFlib.

            1. Choose one CPU version of your DLL, and locate the export .lib file for that CPU.
              A MIPS version of a DLL is ideal. Do not use an x86 version as the base .lib, because its C++ decoration scheme cannot be reversed into a standard form. Any of the RISC CPUs has simpler decoration schemes and is suitable to use as the base .lib.
            2. Prepare an inclusion source file.

              An inclusion source file is a C++ source file that includes all the header files necessary for using the APIs of the target DLL. Prepare this exactly like a normal C++ source file with all the required headers but no source code. If the DLL exports in C style rather than C++, remember to use extern "C" to prevent the compiler from decorating the C function names:

              extern "C" { #include "MyCHeader.h" }

              If there are any exports that are not defined in standard header files and you need to make them accessible to the CEF application, then add the proper definitions to your inclusion source file.

            3. Exclude APIs that should not be accessible to a CEF application.

              There may be exported functions, such as CPU-specific function, in the headers specified by the inclusion source file that should not be accessible to a CEF application. Often specified header files may already surround these with CPU-specific #ifdef statements, thereby avoiding any problem.

              If an API has not been defined for CPU-specific compilation, then the easiest way to make it inaccessible to the CEF application is to #define the exported function name to some other name in the inclusion source file prior to including the corresponding header file. MkCEFlib discards any name that it cannot match to an export in the native .lib file. MkCEFlib also discards any export that it cannot match to a declaration in the inclusion source file. MkCEFlib generates a log that you can use to identify included and discarded functions.

            4. After you prepare the inclusion source file, compile it to be sure that it is free of errors.

              After you complete these steps, you can run MkCEFlib as follows.

              Running MkCEFlib

              After you complete the required preparations, follow these steps to create a CEF import library.

              1. Create a working folder to store the files generated by MkCEFlib. Although this is optional, MkCEFlib can generate many intermediate files that are more easily managed in a separate folder.
              2. Open a command window, and run Wcecef.bat (located in Microsoft eMbedded Tools\EVC\WCEversion\BIN) to set environment variables.
              3. Be sure that any header files specified by the inclusion source file are either in the current directory or in a directory specified by the INCLUDE environment variable.
                Prefix any unspecified paths to the INCLUDE environment variable with the set command (for example, set c:\headers;%include% to prefix "c:\headers" directory to the INCLUDE value).
              4. Run MkCEFlib (see MkCEFlib Command Reference for the correct command line format).

                Actions Performed by MkCEFlib

                When you run MkCEFlib, it performs actions in the following order:

                1. MkCEFlib extracts a list of export names from the native library. It puts these into a text file in the working folder named libName.cefdef. You can inspect the contents of this file to see if a missing API was in the native library. If a native library is not found or if it creates no exports, then MkCEFlib displays an error message and halts.
                2. MkCEFlib preprocesses the inclusion source and creates a source file named inclusionPath.i. This speeds up the remainder of the process and simplifies your investigation if an API does not appear in the log. The preprocessed file clearly shows if the API was not included from the headers.
                3. MkCEFlib performs a trial compilation of the inclusionPath.i preprocessed file to check that it has no errors. If you see any errors at this point, cancel the MkCEFlib process and resolve the errors by looking at the preprocessed file. At this stage, errors are ordinary C++ issues, so you can solve them as you would solve other compilation errors.
                4. MkCEFlib iterates through all the exports, recompiling the inclusionPath.i file with a special switch for each export name. This step normally generates a lot of warnings about missing return types. These warnings are harmless, and you can ignore them.
                5. Finally, after MkCEFlib compiles all the files, it runs the LinkCEF linker to bind them into a library. This completes the process.

                  Troubleshooting MkCEFlib

                  You can see a list of the exports in the workDirPath\libName.log text file. If the export had a problem, it is marked in square brackets; for example, "[MISSING OBJ]". You should examine this log file after running MkCEFlib.

                  The following can cause problems:

                  • The export had no matching declaration in the header files. To check this, compare the .cefdef and the .i files. Carefully compare the fully qualified name if it is C++, and ensure that the .i source code uses extern "C" if the export is not a decorated name.
                  • Many cases of [SMALL OBJ] are "private:" C++ class members. MkCEFlib cannot import these into CEF.

                    MkCEFlib Command Line

                    MkCEFlib creates a .cefdef import library file for a CEF application. The location of Mkceflib.exe is in Microsoft eMbedded Tools\EVC\ WCEversion \BIN. Mkceflib.exe is included with version 3.0 or later of the Windows CE operating system. The default location is specified in the PATH variable created by the Wcecef.bat batch file, also located in Microsoft eMbedded Tools\EVC\ WCEversion \BIN.

                    To run MkCEFlib, use the following command line syntax. MkCEFlib.exe returns 0 if there is no error or 1 if it was unsuccessful.

                    MkCEFlib libname inclusionfile workingfolder
                    The libnamefield is the fully qualified name of a native import .lib file. This corresponds to a CPU version of the DLL.
                    The inclusionfilefield is the fully qualified name of the inclusion source file for the project.
                    The workingfolderis the working directory where MkCEFlib saves all intermediate and result files.

                    Conclusion

                    CEF enables Windows CE application developers to deliver products that support all the CPU architectures that run the Windows CE operating system. Because CEF is an intermediate language, processor vendors can easily add a new CPU family that runs CEF applications. They just port Windows CE to their process and write the CEF compiler.