Integrating your project in the PUBLIC tree


Introduction

 Have you ever wondered how you can integrate your code under the PUBLIC tree in Windows Embedded CE 6.0? This can be useful if you want to distribute code/components that are not part of a BSP. In this post I’ll explain how to create a folder/files structure to handle a couple of projects -a sample device driver and a sample application. This should give to the reader even a different insight into Windows CE build system. To perform the various steps you need to open a workspace (anyone you have at hand) in Platform Builder.

Here you can find a .zip file containing the files and folders described in this post.

Wince.bat

 

Let’s start taking a look around line 290 of %_WINCEROOT%\PUBLIC\COMMON\OAK\MISC\wince.bat you should see this line:

for /D %%f in (%_PUBLICROOT%\*.*) do if exist %%f\cebasecesysgen.bat call :AddDepTree  %%~nf %%f

This line adds to %_DEPTREES% environment variable every directory under %_WINCEROOT%\PUBLIC which contains a file named cebasecesysgen.bat

The %_DEPTREES% environment variable lists the projects that the build system will traverse (http://msdn.microsoft.com/en-us/library/aa909663.aspx); if you open a command prompt from Platform Builder and type set _deptrees you will see something like:

 _DEPTREES=winceos dcom gdiex ie script servers shellsdk shell rdp wceshellfe wce appsfe directx voip datasync netcfv2 netcfv35 sqlcompact SQLCE cellcore ostest m ediaapps speech FP_VOIP workspace_name

If you compare the names listed you will notice that they correspond to the directories under %_WINCEROOT%\PUBLIC  with the addition of winceos and workspace_name: the latter will actually be the name of the workspace you opened in Platform Builder.

Cebasesysgen.bat

 

Create a directory named PUBLICSAMPLE under %_WINCEROOT%\PUBLIC; inside this folder create a cebasecesysgen.bat file with this content:

@REM

@REM (c) Luca Calligaris 2009

@REM This is a sample batch file to integrate custom code in Windows CE public tree

@REM THE SAMPLE SOURCE CODE IS PROVIDED “AS IS”, WITH NO WARRANTIES.

@REM

if /i not “%1″==”preproc” goto :Not_Preproc

    set PUBLICSAMPLE_MODULES=

    goto :EOF

:Not_Preproc

if /i not “%1″==”pass1” goto :Not_Pass1

    if not “%SYSGEN_PUBLICSAMPLE%”==”1” goto :no_publicsample

REM Set required SYSGEN variables         

    if not “%SYSGEN_PUBLICSAMPLE_SAMPLEDRIVER%”==”1” goto no_publicsample_sampledriver

        REM  ==build==

        set PUBLICSAMPLE_MODULES=%PUBLICSAMPLE_MODULES% sampledriver

        REM  ==depend==

        REM  ==conditional==

    :no_publicsample_sampledriver

    if not “%SYSGEN_PUBLICSAMPLE_SAMPLEAPPLICATION%”==”1” goto no_publicsample_sampleapplication

        REM  ==build==

        set PUBLICSAMPLE_MODULES=%PUBLICSAMPLE_MODULES% sampleapplication

        REM  ==depend==

        REM  ==conditional==

    :no_publicsample_sampleapplication

    :no_publicsample

            goto :EOF

:Not_Pass1

if /i not “%1″==”pass2” goto :Not_Pass2

    goto :EOF

:Not_Pass2

if /i not “%1″==”report” goto :Not_Report

    if not “%PUBLICSAMPLE_MODULES%”==””     echo PUBLICSAMPLE_MODULES=%PUBLICSAMPLE_MODULES%

    goto :EOF

:Not_Report

echo %0 Invalid parameter %1

We will examine the content of the file later. If you now open a new command prompt from Platform Builder and type set _deptrees you will see:

_DEPTREES=winceos dcom gdiex ie script servers shellsdk shell rdp wceshellfe wce appsfe directx voip datasync netcfv2 netcfv35 sqlcompact SQLCE cellcore ostest m ediaapps speech FP_VOIP PUBLICSAMPLE workspace_name

As you can notice, PUBLICSAMPLE project has been added to %_DEPTREES% .

Catalog file

 

Let’s create a CATALOG folder under %_WINCEROOT%\PUBLIC/PUBLICSAMPLE. Inside this folder we will put the catalog file for our sample project: we will call it publicsample.pbcxml from the name of the project itself:

<?xml version=”1.0″ encoding=”utf-8″?>

<CatalogFile xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221; xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221; RequiredVersion=”6.00″ xsi:schemaLocation=”urn:Microsoft.PlatformBuilder/Catalog PbcXml600.xsd” xmlns=”urn:Microsoft.PlatformBuilder/Catalog”>

  <FileInformation Id=”FileInformation:YourCompany:Main”>

    <Title>Public Sample</Title>

    <Description>Public Sample Catalog Items</Description>

    <Vendor>YourCompany</Vendor>

    <OSVersion>6.00</OSVersion>

    <FileVersion>1.00</FileVersion>

  </FileInformation>

  <Item Id=”YourCompany:sampledriver”>

    <Title>Public Sample Driver</Title>

    <SysgenVariable>SYSGEN_PUBLICSAMPLE_SAMPLEDRIVER</SysgenVariable>

    <Variable>SYSGEN_PUBLICSAMPLE</Variable>

    <Module>sampledriver.dll</Module>

    <Location>Public Sample\Device Drivers</Location>

    <SourceCode>

      <Title>Public Sample Driver Source Code</Title>

      <Path>$(_WINCEROOT)\PUBLIC\PUBLICSAMPLE\OAK\DRIVERS\DRIVER</Path>

    </SourceCode>

  </Item>

  <Item Id=”YourCompany:sampleapplication”>

    <Title>Public Sample Application</Title>

    <SysgenVariable>SYSGEN_PUBLICSAMPLE_SAMPLEAPPLICATION</SysgenVariable>

    <Variable>SYSGEN_PUBLICSAMPLE</Variable>

    <Module>sampleapplication.exe</Module>

    <Location>Public Sample\Applications</Location>

    <SourceCode>

      <Title>Public Sample Application Source Code</Title>

      <Path>$(_WINCEROOT)\PUBLIC\PUBLICSAMPLE\OAK\APPLICATIONS\APP</Path>

    </SourceCode>

  </Item>

</CatalogFile>

I will not discuss the syntax of the catalog file here: notice that we are basically creating two catalog items -one for the driver and one for the application- and we are defining the sysgen variables for the items themselves. When you’ll select the item the corresponding variable will be set and when our cebasecesysgen.bat will be called it will set PUBLIC_SAMPLE_MODULES accordingly to the items selection.

Go back to Platform Builder and click the refresh button in Catalog Items View: you should see something like:

The FILES folder

 

To follow the structure of the other public projects we will now create a folder named OAK

under %_WINCEROOT%\PUBLIC/PUBLICSAMPLE then, under that we will create the folder structure for our project files:

%_WINCEROOT%\PUBLIC/PUBLICSAMPLE/OAK

                        |

                        |_FILES

                                   |_INTLRTNS

                                               |_0409

                                               |          

                                               |_0410

 Under %_WINCEROOT%\PUBLIC/PUBLICSAMPLE\OAK\FILES  we will put the configuration files for our project:

  1. publicsample.bib:

 

MODULES

;   Name                    Path                                            Memory Type

;   ————–          ———————————-         ———–

; @CESYSGEN IF PUBLICSAMPLE_MODULES_SAMPLEDRIVER

sampledriver.dll             $(_FLATRELEASEDIR)\sampledriver.dll                             NK  SHK

; @CESYSGEN ENDIF

; @CESYSGEN IF PUBLICSAMPLE_MODULES_SAMPLEAPPLICATION

sampleapplication.exe                $(_FLATRELEASEDIR)\sampleapplication.exe        NK

; @CESYSGEN ENDIF

FILES

;   Name                    Path                                            Memory Type

;   ————–          ———————————-         ———–

; @CESYSGEN IF PUBLICSAMPLE_MODULES_SAMPLEAPPLICATION

sampleapplication.lnk                 $(_FLATRELEASEDIR)\sampleapplication.lnk         NK SH

; @CESYSGEN ENDIF

  1. publicsample.reg:

 

; @CESYSGEN IF PUBLICSAMPLE_MODULES_SAMPLEDRIVER

[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\SampleDriver]

            “Prefix”=”SDR”

            “Index”=dword:0

            “Dll”=”sampledriver.dll”

            “Order”=dword:66

            “Description”=LOC_PUBLIC_SAMPLE_DRIVER

; @CESYSGEN ENDIF

  1. publicsample.dat:

 

; @CESYSGEN IF PUBLICSAMPLE_MODULES_SAMPLEAPPLICATION

Directory(“\Windows\LOC_PROGRAMS_DIR”):-File(LOC_SAMPLEAPPLICATION_LNK, “\Windows\sampleapplication.lnk”)

; @CESYSGEN ENDIF

  1. sampleapplication.lnk:

 

30#\Windows\sampleapplication.exe

In all publicsample.* files we condition the settings to the sysgen variables we have defined before.

In the .dat file we will put a shortcut to sampleapplication.exe in \Windows\Programs so that the sample program will appear in Start Menu -> Programs. Notice that we are using LOC_XXX macros in the files so we will be able to localize our project.

The localization files (publicsample.str) will find their place under the relevant locale folders in %_WINCEROOT%\PUBLIC/PUBLICSAMPLE\OAK\FILES\INTLTRNS:

  1. publicsample.str in 409 (for English language):

 

#define LOC_PUBLIC_SAMPLE_DRIVER                 “Public Sample Driver”

#define LOC_SAMPLEAPPLICATION_LNK               “Public Sample Application.lnk”

 

  1. publicsample.str in 410 (for Italian language):

 

#define LOC_PUBLIC_SAMPLE_DRIVER                 “Driver per Public Sample”

#define LOC_SAMPLEAPPLICATION_LNK               “Applicazione per Public Sample.lnk”

Source code

 

We will now create the file system structure for our source code:

%_WINCEROOT%\PUBLIC/PUBLICSAMPLE/OAK

                        |

                        |_DRIVERS

                        |           |_SAMPLEDRIVER

                        |

                        |_APPLICATIONS

                                   |_SAMPLEAPPLICATION

Since we’re using boilerplate code for both the application and the driver I will not dwell on it; both the application and the driver will simply use RETAILMSG to signal that they are running; the thing you have to notice is the following: the sources files for SAMPLEDRIVER and SAMPLEAPPLICATION will produce a static library:

  1. sampledriver sources file:

 

TARGETNAME=sampledriver_lib

RELEASETYPE=OAK

TARGETTYPE=LIBRARY

TARGETDEFNAME=sampledriver

DEFFILE=$(TARGETDEFNAME).def

WINCETARGETFILE0=$(_RELEASELIBDIR)\$(TARGETDEFNAME).def

INCLUDES=..\..\INC

SOURCES=sampledriver.c

  1. sampleapplication sources file

 

TARGETNAME=sampleapplication_lib

RELEASETYPE=OAK

TARGETTYPE=LIBRARY

INCLUDES=..\..\INC

SOURCES= \

    sampleapplication.cpp \

 

the driver .DLL and the application .EXE will be created during the sysgen phase with the help of our project makefile which is described in the following paragraph. To instruct the build system about our source code organization we have to add some other files here and there:

  1. %_WINCEROOT%\PUBLIC/PUBLICSAMPLE/dirs:

 

DIRS=OAK

 

  1. %_WINCEROOT%\PUBLIC/PUBLICSAMPLE/OAK/dirs:

 

DIRS=DRIVERS APPLICATIONS

 

  1. %_WINCEROOT%\PUBLIC/PUBLICSAMPLE/OAK/DRIVERS/dirs:

 

DIRS=SAMPLEDRIVER

 

  1. %_WINCEROOT%\PUBLIC/PUBLICSAMPLE/OAK/APPLICATIONS/dirs:

 

DIRS=SAMPLEAPPLICATION

  1. %_WINCEROOT%\PUBLIC/PUBLICSAMPLE/sources.cmn:

 

WINCEPROJ=publicsample

RELEASETYPE=OAK

DOSYSGEN=1

WARNISERROR=1

# OS projects during compile always get the full unfiltered headers & build into their own public tree.

_COMMONPUBROOT=$(_PUBLICROOT)\common

__PROJROOT = $(_PUBLICROOT)\$(WINCEPROJ)

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

In the latest file we define some macros that will be shared by all the projects.

Makefile

 

We will now create a CESYSGEN folder in %_WINCEROOT%\PUBLIC/PUBLICSAMPLE: in this folder we will put an empty sources file and we will create a makefile with this content:

!if 0

Copyright (c) Luca Calligaris 2009

!endif

!if 0

Use of this sample source code is subject to the terms of the Microsoft

license agreement under which you licensed this sample source code. If

you did not accept the terms of the license agreement, you are not

authorized to use this sample source code. For the terms of the license,

please see the license agreement between you and Microsoft or, if applicable,

see the LICENSE.RTF on your install media or the root of your tools installation.

THE SAMPLE SOURCE CODE IS PROVIDED “AS IS”, WITH NO WARRANTIES.

!endif

WINCEPROJ=publicsample

#

# Include shared SYSGEN makefile

#

!INCLUDE $(_PUBLICROOT)\common\cesysgen\cesysgen.mak

preproc: $(PUBLICSAMPLE_MODULES) files

postproc:

#

# These are parts of the sysgen process not associated with any modules. They are always run.

#

includes:

        @echo Processing include files

        $(SG_TOKENFILTER) $(SG_INPUT_ROOT)\oak\inc\*.* $(SG_OUTPUT_ROOT)\oak\inc

        $(SG_TOKENFILTER) $(SG_INPUT_ROOT)\sdk\inc\*.* $(SG_OUTPUT_ROOT)\sdk\inc

files:

            $(SG_TOKENFILTER) $(SG_INPUT_ROOT)\oak\files\$(WINCEPROJ).* $(SG_OUTPUT_ROOT)\oak\files

            -@xcopy /D /I $(SG_INPUT_ROOT)\oak\files\*.lnk $(SG_OUTPUT_ROOT)\oak\files

            -@xcopy /i /e /q /c /D $(SG_INPUT_ROOT)\oak\files\intltrns $(SG_OUTPUT_ROOT)\oak\files\intltrns

##############################################################

# These are modules which link as part of the sysgen phase, but are not componentized.

# This includes everything else in PRIVATE\WINCEOS except those that have explicit rules above

# When you add your module here, please follow the 4-step instructions laid down below.

##############################################################

#

# STEP1: List your dependencies (other things that must link before you in the sysgen phase) and

#        set your TARGETLIBS variable. List your link libs & RES files first and your import libs last

#        Don’t list coredll.dll. It will be included by default. Don’t set SOURCELIBS. It is not used

#        in this phase. Also note that all rules in this section must end in :: not :

#

# IMPORTANT: Don’t forget to list your dependencies. Anything you list in TARGETLIBS that also builds

# in *this* makefile *must* be listed as a dependency. DO NOT list stuff built elsewhere, such as in

# the WINCEOS tree’s sysgen phase

## Some useful generic macros

OWNLIB=$(SG_INPUT_LIB)\$@.lib

OWNSTATICLIB=$(SG_INPUT_LIB)\$@_lib.lib

OWNRES=$(SG_INPUT_LIB)\$@.res

OWNLIB_RES=$(SG_INPUT_LIB)\$@.lib $(SG_INPUT_LIB)\$@.res

CCLIB=$(SG_OUTPUT_SDKLIB)\commctrl.lib

WINSOCKLIB=$(SG_OUTPUT_SDKLIB)\winsock.lib

WS2LIB=$(SG_OUTPUT_SDKLIB)\ws2.lib

WS2KLIB=$(SG_OUTPUT_OAKLIB)\ws2k.lib

CEOSUTILLIB=$(SG_OUTPUT_SDKLIB)\ceosutil.lib

OTHERS_ROOT=$(_WINCEROOT)\others

CEDDKLIB=$(SG_OUTPUT_OAKLIB)\ceddk.lib

OLELIBS=$(SG_OUTPUT_SDKLIB)\uuid.lib $(SG_OUTPUT_SDKLIB)\ole32.lib $(SG_OUTPUT_SDKLIB)\oleaut32.lib

sampledriver sampleapplication  ::

                @set TARGETLIBS=$(OWNSTATICLIB)

##############################################################

# STEP-2: Add your module to exactly ONE of the following two RELEASETYPE rules

##############################################################

sampledriver sampleapplication::

            @set RELEASETYPE=OAK

            @set CPL=

# ::

#          @set RELEASETYPE=SDK

#          @set CPL=

##############################################################

# STEP-3: For .CPLs only! If (and only if) your module needs to be renamed from .DLL to .CPL

##############################################################

# ::

#          @set CPL=1

##############################################################

#

# STEP-4: Add your module to exactly ONE of the following rules, choosing your

#         DLL or EXE entry point.

#

#         NOTE: DO NOT create new rules.

#

#         NOTE: It is necessary to initialize the C Runtime in order to call C++

#         static ctors & dtors and to initialize the compiler security checks (/GS

#         switch).  In almost all cases, entrypoints that do not initialize the

#         C Runtime should not be used.

#

# _DllEntryCRTStartup — Initializes the C Runtime, then calls module’s DllEntry

# _DllMainCRTStartup  — Initializes the C Runtime, then calls module’s DllMain

# WinMainCRTStartup   — Initializes the C Runtime, then calls module’s WinMain

# wWinMainCRTStartup  — Initializes the C Runtime, then calls module’s wWinMain

# mainWCRTStartup     — Initializes the C Runtime, then calls module’s wmain(int argc, wchar_t *argv[]) (CONSOLE APP)

# mainACRTStartup     — Initializes the C Runtime, then calls module’s main(int argc, char *argv[]) (CONSOLE APP)

#

# DllEntry/DllMain    — calls entry supplied by module. Does NOT initialize the C Runtime

# WinMain             — calls module’s standard EXE entry point. Does NOT initialize the C Runtime

#

##############################################################

sampledriver ::

            @set TARGETTYPE=DYNLINK

            @set DLLENTRY=_DllEntryCRTStartup

            @set TARGETNAME=$@

            @set DEFFILE=$(SG_INPUT_LIB)\$@.def

            @set SOURCELIBS=

            @set TARGETLIBS=%%TARGETLIBS%% $(SG_OUTPUT_SDKLIB)\coredll.lib

            $(MAKE) /NOLOGO $(SG_OUTPUT_OAKTGT)\$@.dll

# ::

#          @set TARGETTYPE=DYNLINK

#          @set DLLENTRY=_DllMainCRTStartup

#          @set TARGETNAME=$@

#          @set DEFFILE=$(SG_INPUT_LIB)\$@.def

#          @set SOURCELIBS=

#          @set TARGETLIBS=%%TARGETLIBS%% $(SG_OUTPUT_SDKLIB)\coredll.lib

#          $(MAKE) /NOLOGO $(SG_OUTPUT_OAKTGT)\$@.dll

# ::

#          @set TARGETTYPE=DYNLINK

#          @set DLLENTRY=DllEntry

#          @set TARGETNAME=$@

#          @set DEFFILE=$(SG_INPUT_LIB)\$@.def

#          @set SOURCELIBS=

#          @set TARGETLIBS=%%TARGETLIBS%% $(SG_OUTPUT_SDKLIB)\coredll.lib

#          $(MAKE) /NOLOGO $(SG_OUTPUT_OAKTGT)\$@.dll

# ::

#          @set TARGETTYPE=DYNLINK

#          @set DLLENTRY=DllMain

#          @set TARGETNAME=$@

#          @set DEFFILE=$(SG_INPUT_LIB)\$@.def

#          @set SOURCELIBS=

#          @set TARGETLIBS=%%TARGETLIBS%% $(SG_OUTPUT_SDKLIB)\coredll.lib

#          $(MAKE) /NOLOGO $(SG_OUTPUT_OAKTGT)\$@.dll

# ::

#          @set TARGETTYPE=PROGRAM

#          @set EXEENTRY=WinMain

#          @set TARGETNAME=$@

#          @set SOURCELIBS=

#          @set TARGETLIBS=$(SG_OUTPUT_SDKLIB)\coredll.lib %%TARGETLIBS%%

#          $(MAKE) /NOLOGO $(SG_OUTPUT_OAKTGT)\$@.exe

sampleapplication ::

            @set TARGETTYPE=PROGRAM

            @set EXEENTRY=WinMainCRTStartup

            @set TARGETNAME=$@

            @set SOURCELIBS=

            @set TARGETLIBS=$(SG_OUTPUT_SDKLIB)\coredll.lib %%TARGETLIBS%%

            $(MAKE) /NOLOGO $(SG_OUTPUT_OAKTGT)\$@.exe

# This is a special rule for DLLs that want their DEF file filtered for componentization

#

# ::

#          @set TARGETTYPE=DYNLINK

#          @set DLLENTRY=DllEntry

#          @set TARGETNAME=$@

#          @set DEFFILE=$(SG_OUTPUT_OAKLIB)\$@.def

#          $(SG_TOKENFILTER) $(SG_INPUT_LIB)\$@.def $(SG_OUTPUT_OAKLIB)

#          @set SOURCELIBS=

#          @set TARGETLIBS=%%TARGETLIBS%% $(SG_OUTPUT_SDKLIB)\coredll.lib

#          $(MAKE) /NOLOGO $(SG_OUTPUT_OAKTGT)\$@.dll

##############################################################

# STEP-5: If (and only if) your module has a localizable RES file, add it to the first

#         line below. This creates a text file that is used during MAKEIMG to insert

#         the correct localized resources.

##############################################################

#################### END of 5-STEP standardized default SYSGEN LINK PHASE######

Most part of the file content is commented since several rules are not actually used by our projects. You can examine the various makefiles in the public projects to see more complex examples.

In the preproc phase the makefile will process $(PUBLICSAMPLE_MODULES) and files: rules for files will copy out from our project the publicsample.* files, the shortcut and the *.str files for localization. The rules for $(PUBLICSAMPLE_MODULES) (i.e sampledriver and/or sampleapplication) tell the build system how to build our targets: the TARGETLIBS macro for both the executable is defined as $(OWNSTATICLIB) which is defined as <module name>_lib.lib which is what it’s built by sources files; both the targets have the same directive RELEASETYPE=OAK. The other build rules are different since we are building a dynamic link library in a case and an application in the other.

Advertisements
This entry was posted in Windows Embedded CE and tagged , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s