Building Native C++ Applications that Will Run on Microsoft Pocket PC and Windows CE .NET Platforms

 

Kirk Radeck, Windows Embedded MVP
Senior Software Engineering Consultant

July 2002

Download Tictactoezip kirk radeck.exe.

Applies to:
    Microsoft® Windows® CE .NET 4.0
    Microsoft Pocket PC

Summary: Pocket PC developers currently face the following dilemma: they want to build applications that will run on Pocket PC devices, and benefit from expanded market opportunities by having these same applications run under Windows CE .NET. This paper will discuss an approach to developing retargetable applications to multiple Microsoft platforms. In addition, a sample application and its sources are included to demonstrate the methodology. (17 printed pages)

Contents

Introduction
Initial Testing
What's the Real Goal?
Recommendation
Sample Application
Conclusion
Appendix 1
Appendix 2
Appendix 3
References

Introduction

Microsoft® Pocket PC development currently requires the use of Microsoft eMbedded Visual C++® 3.0 (eVC3) with the Pocket PC SDK installed, while native Microsoft Windows® CE .NET applications must be compiled using eMbedded Visual C++ 4.0 (eVC4) with the STANDARDSDK Emulator for debugging. Each of these tools must either be installed on two separate computers, or on the same computer with at least two hard drive partitions. The former approach is better for several reasons (you can use both tools simultaneously is one).

However, C++ is generally C++. Even MFC is mostly MFC, regardless of the platform being targeted. If a developer uses some strategy, he should be able to build and compile most of his embedded code using nearly any one of his favorite Microsoft IDEs, such as Microsoft Visual Studio® 6.0. This would require that the code being written is already fairly portable as it must at least compile and run for the desktop and one embedded device.

Initial Testing

Approaching the challenge to discover if applications can run on both Pocket PC and Windows CE .NET devices, initial testing included sampling some current Pocket PC applications. If an application was created for the Pocket PC before the release of eVC4, where that application compiles and runs with no application code change in the new Emulator, then it surely can be done with at least some new applications. Developers now have knowledge about both tools.

With eVC3 installed on one computer, it is possible to iterate the <drive>:\Windows CE Tools\wce 300\MS Pocket PC\samples\mfc subdirectories and do the following:

  • Create a new project with the same name and project type as the current subdirectory project on a machine with eVC4 installed
  • Copy all Pocket PC files, minus the project files, to the new project directory and add to the new project
  • Make any necessary project setting changes to the new project
  • Compile and run the new project using the Emulator

Most, if not all, of these projects compile and run in the Emulator (see Appendix 1 and Appendix 2, which describe this process for both MFC and Win32 applications).

This shows that it is possible to build some, if not all, applications that can run on both Pocket PC devices and the eVC4 Emulator by simply creating a Windows CE .NET project and recompiling.

What's the Real Goal?

While it would be nice to build applications that can run on both the Pocket PC and Windows CE .NET, the real goal is to build applications that can be built and run on any Microsoft Windows platform with no code change. After all, with the release of good, portable object-oriented languages such as C# in Visual Studio.NET (Visual Studio .NET), developers can attain this goal.

But asking eVC3-4 to have this level of portability may be asking too much, since these tools weren't originally designed to be this flexible. Also, there are differences in application behavior between the Pocket PC and Windows CE .NET devices. For example, the set of standard MenuItems for the Pocket PC are quite different that those for a desktop application. A single stylus click on a Pocket PC is equivalent to a left double-click on a CE device with mouse support. Screen sizes and shapes vary widely from platform to platform. There are many usability issues that a developer needs to address for any device and operating system being built against, and so forth.

Recommendation

One possible solution is to make a slight compromise: build layered software where most of the code can be reused. Most of these layers could be completely portable across Microsoft platforms, only requiring at most a recompile for a specific device. Perhaps only parts of the user interface could be platform specific where the developer has knowledge of the device he is building against. This would allow a write-once, use-many scenario for the majority of the code in static or dynamic libraries, while allowing all versions of the application to use these libraries and the flexibility to override default library behavior if desired.

Software Layers

Assuming that a user interface will be needed for the platform-specific application(s) then a simple set of layers could be defined and built.

Back-end Processing

What does your application really do? If you removed the GUI, what functionality do you need to support? For example, a very simple CelsiusToFahrenheit program would have support to accept a temperature in Celsius degrees and return its value in Fahrenheit. One definition of this function, accepting a double Celsius value and returning its corresponding Fahrenheit conversion, is:

double CelsiusToFahrenheit(double celsius);

This layer should be a library only as it will be imported into some application for use. If possible, making this layer ANSI C++ compliant is also a good idea.

Graphics Layer

If you remove the main frame, menu items, and so forth from your application, what components would you need? For example, in your CelsiusToFahrenheit program, you would need to accept a Celsius value from the user and display its corresponding Fahrenheit value. You would probably need a CWnd childframe object, call it "CelsiusFrame"; a label and text field for the Celsius input; two labels for the Fahrenheit conversion (one displaying "Fahrenheit" and the other to display the converted value); and two buttons, one each for the user submission and to clear the form.

You may create and implement default event handlers for the buttons, which would display values to the components on the CelsiusFrame. CelsiusFrame may define some operations that the calling application may need, for example—Clear() for resetting all child components to default values. This operation set would usually include a combination of standard event handler functions, and user-defined virtual functions as needed.

This layer will use the back-end processing header files, and it will be a library itself.

Application Layer

This layer might be an MFC application, with at least a CWnd mainframe, and a CWnd childframe. It would import the Graphics layer above, and the childframe would subclass the CelsiusFrame. It would define and implement event handlers for the MenuItems that are necessary. The event handlers can then simply call into the Graphics layers to do the actual work.

In this example, a possible MenuItem might be "File\Clear Form". The application layer would define and implement this item and its event handler. When the event handler is called, it would call the user-defined Clear() function in the Graphics layer and return.

With this layered approach, it should be noted that no application-layer logic may be necessary for accepting user input from CelsiusFrame. If CelsiusFrame is responsible for its own event handling, the application doesn't even have to know that the logic exists. The application layer's childframe only needs to inherit from the CelsiusFrame and call into a set of simple user-defined functions that the graphics layer supports.

Layer Pros

There are many advantages to using this recommendation.

  1. The back-end processing and graphics layers are very portable. At most the developer should only have to create library projects with the IDE project wizard, add the source files, modify some project settings, and compile.
  2. With a good design the application layer should be able to override behavior in the libraries if necessary. Reverting to the CelsiusToFahrenheit example above, maybe the Pocket PC version will display a MessageBox if the user enters illegal data (the temperature is below absolute zero?) while a desktop version may write additional information to the status window.
  3. The application code will remain manageable and readable. The MessageBox and the status window example can naturally be handled in one piece of code, but it may not be desirable. Real-world applications tend to become more complex over time, not less. Detecting a device at run-time or using preprocessor directives to remove code at compile time based upon device will certainly make code more difficult to understand.
  4. Application development can be broken into logical blocks. This will help companies building complex software by allowing them to have developers work in parallel. If you build one monolithic application, it is possible but more difficult to have several developers work on separate pieces of the project.
  5. Quality assurance will become a potential nightmare if only one application exists. With this recommendation, retesting for all device types will only be required if a back-end or graphics layer changes. Adding a new feature at the end of a release cycle may be possible in only one platform's application layer; it requires only a retest on that platform, provided a good design.
  6. Client-server applications are already built in this manner. While it doesn't prove that this is the best approach, it does show that this is not really a new problem and that others have chosen this approach to solve similar problems with success in the past.
  7. Fix one, fix all. If you find a bug in a non-application layer and fix it correctly, it will then update all applications with just a recompile for each device type.

Layer Cons

Unfortunately, there are some cons to this recommendation, albeit not enough to completely abandon the layered approach.

  1. Building extremely simple applications tends to require more time, because there is setup time involved creating layered software. Projects need to be created; settings need to be adjusted and maintained, and so on.
  2. Debugging the application is a little trickier. You may have to build driver programs to test your libraries. In a single application, you can simply set a breakpoint and run the debugger. But this issue is only a minor inconvenience. Microsoft IDEs have very good support for debugging not only applications, but also library projects. For example, in Visual Studio 6.0: if you open the "Project\Settings. . ." Dialog in a static library project, select the "Debug" tab, select "Settings for: Win32 Debug", you can set the "Executable for debug session:" to some console or MFC application driver that uses this library. Set the "Executable for debug session:" value to the absolute path on your local drive where the driver debug executable exists. You can then set break points in your library, then "run" your library, which executes the driver and stops at the first breakpoint set.
  3. The libraries that developers create will tend to be written to the least common denominator—the platform that supports the smallest API set. There are ways around it—callback interfaces to the client layer, extern functions, DLLs, and so on. But this is the biggest issue that must be addressed and negotiated.
  4. You may have to build code to perform some task, where the support already exists in some but not all platforms your code needs to run on. But this is not a huge problem, because you need the support on the platform that doesn't have it. This implies that it needs to be built or supplied anyway.

Things to Remember

As you are building these layers there are some things you should keep in mind.

  1. In "good" client-server applications, the client generally knows much more about the server than vice-versa. While a layer is being built it is fine to have knowledge about some library that you are using (at least at the API level), but you shouldn't know much about the client who will be using this layer. Good use of callback functions such as using interfaces defined at the server layer is one way to get application-specific information from the client; using events and so forth are other ways. This may seem trivially obvious, but it is easy to forget during development.
  2. As the layers are being built bottom-up, the code written should become more and more platform specific. For example, at the application layer it is completely fine and maybe even desirable to have some knowledge about the platform being targeted. At the graphics layer, the code should not need to know that the platform is a Pocket PC device.

Testing the Recommendation

It would be unfair to make a recommendation and then leave the developer on his own to test if it is reasonable. A sample application using the layered approach has been developed and included with this paper that will run on Pocket PC and the Windows CE .NET emulators, as well as the desktop.

Sample Application

While a TicTacToe program is relatively simple, it is a reasonable candidate as a portable application sample. It requires back-end processing, which is just a virtual game board with current state, some square access functions and a FindBestMove method for the current player in case it is the computer's turn to play (in a complex game, you could even use this method to recommend a move to the human player while he is thinking). It needs a graphics layer that can display a graphical representation of a board and accept and process input from the user (even though the game of TicTacToe is not very interesting, it would be more uninteresting if no one played). And it needs an application layer that the user can start, where this application displays a frame with MenuItems and in turn drives the graphics layer. (See Appendix 3 describing how to build an application using the included source files. TicTacToe.exe, which runs on Microsoft Windows 2000 Professional and Server and Windows XP, can be found in the included files' exe\WindowsDesktop folder.)

Tools Used

Visual Studio 6.0 was used to create the majority of the TicTacToe code. Why was this tool chosen over eVC3 or 4?

  • Debugging using the eMbedded Visual C++ tools can be slow in some circumstances. One of eVC's greatest strengths creates an unfortunate weakness: the ability to run in emulation, which is great when developing real applications for devices, can be slow while debugging, at least compared to Visual Studio 6.0. It is most probable that there exists no way around this by Microsoft, or developers while using these tools.
  • If something can be done in Visual Studio 6.0, it can usually be done also in eVC3, the latter being used for the creation of Pocket PC applications. Modifying project settings, adding new classes, and so forth are very similar in these tools. So back-porting to eVC3 simply requires copying files and building a project, assuming that no libraries are used which eVC3 does not support.

Why not Visual Studio .NET?

  • The Visual Studio .NET wizard-generated class files may have to be modified slightly in case they are back ported. This is a minor issue, but it helped sway the decision to use Visual Studio 6.0.

  • The Visual Studio .NET library projects are quite different than those in eVC3 or Visual Studio 6.0. This would have required a learning curve at the time, which isn't the point of this project.

    Personal Note   I have written much more C# than C++ code with Visual Studio .NET. This had a large impact on the decision above. In the future, if I were to build an application for the desktop I would probably only use Visual Studio .NET because I believe that it is far superior to Visual Studio 6.0 in many ways, with little to no feature loss.

    When the .NET Compact Framework (CF) is released for Windows CE in the second half of 2002, both Visual Studio .NET and C# both are good candidates for future product development. I believe that companies that do not at least evaluate using C# for new products (and maybe even product ports) will be making a mistake, because C# has such a rich library already and it is highly portable by the nature of the language syntax.

    The built-in Unicode String and internationalization support is excellent. There are many other benefits that go beyond the scope of this paper. Therefore, it would be great (ironically) if this recommendation actually becomes obsolete by the end of this year, because it may mean that more developers are using Visual Studio .NET and C#.

TicTacToe Construction

The TicTacToe sample program currently runs on the desktop (tested on Windows 2000 Professional and Server, and Windows XP Professional), the Pocket PC eVC3 emulator, and the Windows CE .NET emulator. It was constructed in layers, which later drove the above recommendation.

TicTacToe Engine

This back-end processing layer is nearly ANSI C++ compliant, minus a typdef'd String class, which is just an MFC CString that is used for debugging only.

Main classes

Board

This is a TicTacToe board, which holds a BitVector [Lippman] instance of default length 18 (two bits are needed per square, because a piece can be either an x, an o, or empty). One bit turned off implies the square is empty, while the other defines the piece type. This encoding, while not completely necessary, is good because it makes copying a board very fast—only one int is required to hold the state of a board. Many board copies are done when the call is made to find the best move given current state. And other operations such as testing the emptiness of a square are generally fast operations with an encoding of this nature.

A default board's square set is defined in the following manner:

0 1 2

3 4 5

6 7 8

Piece

A piece is either an x, an o, or empty. This class hides the details of the board's encoding from callers. It has common methods like:

Bool IsX() const;
Bool IsO() const;
Bool IsEmpty() const;

Square

This is just an int wrapper, defining the square that a Piece maps to.

Value

This class defines the value of a Move (described below). It can either be undefined, negativeInfinity, tie, or positiveInfinity. It also holds the depth in the search function that the result was determined.

Move

This holds a Piece, a Square, and a Value. The Board's FindBestMove function returns a Move copy, describing the "best" current Move based upon state. More will be described about this below.

TicTacToe Graphics

This graphics processing layer is Microsoft platform agnostic. It uses some MFC classes, and some hand-built classes, for drawing a board to a CWnd object and handling most user events. It uses the .h file function prototypes defined in the TicTacToe Engine layer only as it is a static library itself.

Main Classes

BoardThread

This class holds a Board copy and some event handles. It handles long processing during the call to the FindBestMove function on its board. It calls back on an interface once FindBestMove returns on the Board instance, as long as the thread has been started and it hasn't been yet asked to stop.

BoardGraphics

This holds a CWnd object to draw to, as well as a pointer to the current BoardThread instance (or NULL). It also holds a Board instance so that it can convert the current board state to a graphical representation. It implements the interface for callbacks made in the BoardThread.

CTicTacToeViewBase

This class was constructed automatically during a project creation by Visual Studio 6.0, then modified to hold a BoardGraphics object and renamed. It has event handlers for mouse clicks by the user, and for standard paint events. This class can be used directly by applications that import this library, or subclassed by the applications childframe class, the latter being better.

The BoardGraphics implementation could have been placed in this class. However, it is a good idea to separate the functionality into two classes, because the BoardGraphics can handle events and graphics on any CWnd class, not just the CTicTacToeViewBase.

TicTacToe

This is the simplest MFC application, with a CWnd main frame and childframe instances. It imports the TicTacToeEngine and TicTacToeGraphics libraries, and uses the .h file prototypes of each.

The childframe subclasses the CTicTacToeViewBase class (defined above). MenuItems were added using the resource wizards, and event handlers were created for both the mainframe and childframes, which only make simple one-line calls into the TicTacToeGraphics layer.

Problems During Construction

One problem was encountered during the construction of the application. STL was not supported until eVC4. At least one platform application needed to be constructed using eVC3 (Pocket PC SDK). A list template and BitVector were needed in the TicTacToeEngine library. This required hand-building a list template with equivalent functionality as the STL version (only the methods needed were coded), and the construction of a BitVector class. The list class can be swapped out with Microsoft's implementation on some platforms if desired, as the template name, function names and parameters are identical. The BitVector is not STL-standard, so it cannot be replaced with Microsoft's STL version.

Converting the Sample to Real Software

Assuming that a TicTacToe program is marketable, there are some changes that could be made to make it better. This is only a sample, and it is only version 1.0. Many changes would need to be made to make it "good" for purposes other than this paper.

  1. A MessageBox pops up in the graphics layer over the CTicTacToeViewBase instance when the user tries to do something illegal (select a square that's currently populated, select a square while the computer is thinking, and so forth). A much better implementation would be to use this as default behavior, but allow the application layer to override it by receiving some message event, and then doing whatever it wants with this event. An event is a good idea in this scenario, because time is not very critical; even a one to two second response time back to the player is fine.
  2. The FindBestMove implementation in the TicTacToeEngine layer doesn't really find the best move. If two moves are considered equal, then a random number generator chooses between the two, which seems reasonable so that the next game may be different. But the computer doesn't try to "cheapo" the human player; it assumes currently that the human will always make the right decision so it doesn't try to take advantage of him unless he makes a real mistake.
  3. The computer seems to never lose. It needs to sometimes make a bad decision and let the human take advantage of this. But it's not completely clear, from strictly a requirements point of view, how this should be accomplished (when do you make a bad move? How do you choose a bad move?). This would actually be fun to think about and work on, but beyond the scope of this sample.
  4. The GUI could be much more polished. While it scales correctly for any device, it simply draws the board using lines and ellipses and stock colors. It would be nice to load some bitmaps that would make it more appealing.
  5. More code could be pushed back to the graphics layer from the application. Two of the three application versions create a CTTTInfoDialog, which describes the basic rules of the game. If this were pushed back into the graphics layer and built generically, then it could be reused across all applications and save coding time.
  6. Assuming that a TicTacToeEngine actually has some real value, it would be nice to create one more project layer. If an ATL project were created that used the static engine library, with this ATL project having a very thin interface for board access functions, then this new DLL could be used by any application residing on the device.
  7. An overall redesign would help. For example, the engine layer should define a BoardBase object, which would be a pure virtual class. This would simply define standard accessor functions into the board and have no implementation. The Board class would subclass BoardBase, and provide the default library implementation. In the graphics layer, a BoardGraphics object would hold a pointer to a BoardBase instance and create a new Board instance by default. The application layer could then subclass Board (or BoardBase, if it wants a complete overhaul) in its project, and override any methods it wants, then put this new class object into the BoardGraphics instance for processing through some standard accessor function. Using an object-oriented approach like this would enhance the ability of any platform application to override any behavior that it chooses. Overrides in this sample seem to not be very important, but in some complex software it may be critical—it may make the difference in meeting a critical deadline and not.

Testing Portability During Development

If you build your project in eVC3 for the Pocket PC, for example, this Microsoft IDE will give you a lot of help. Not only can you run some emulator for the Pocket PC, but the compiler will also tell you at compile time if some library function is not supported for this particular device. This is one of the strengths of this tool. However, this recommendation tells you that you can build most of your code in Visual Studio 6.0 or even Visual Studio .NET, but this advice seems to eliminate some of the features the eVC3 already has given you, thus making the job more difficult.

Your original goal is to build for the Pocket PC and Windows CE .NET platforms. You already need to use two tools, at least for now. If you really want to know if your Pocket PC code will run in the emulator in eVC4 for Windows CE .NET, you will have to test it on both eVC3 and 4 anyway. The idea is you can use any Microsoft tool that will do the job. Just choose the one that you have, you feel most comfortable with, or the one that makes the most sense.

The real main issue is this: how do you test portability during development without having to constantly test your code on all platforms? It is best to be able to build code for as long as possible, and then test only occasionally. If you could make the assumption that "if it compiles it works" (usually just a funny joke, depending upon perspective) then it would make the job easier by allowing you to do the following:

  1. foreach problem p do

    API s := null

    While s = null do

  2. Select next candidate API a on p

    If a = null

    break

  3. foreach Microsoft IDE tool t necessary do

    1. Open "Help\Index" Dialog in t

    2. Type a into index field and enter

    3. if a not found then

      break

    4. Scroll to "Requirements Table" rt in right panel

    5. if any necessary platform not in rt or APIs not exactly equivalent then

      break

    6. if t is last tool then

      s := a

      break

  4. if s = null

    s := portable hand-built solution

  5. Use s on p in your favorite Microsoft IDE

Basically, what the above pseudo-code means: you will be required to hand-build a solution for any problem only if there exists no current Microsoft-provided API which solves the problem for all necessary platforms.

Naturally, you will have to test your code on all platforms to verify that it is portable. "If it compiles it works" is certainly not true. But it is true that "if it doesn't compile it doesn't work." Taking this approach allows you to work for extended periods of time without testing code on different platforms. You can then just test on one platform, and if the code runs properly, there is a good chance that it will run on all of them. If you are wrapping MFC or Win32 calls with your own classes, then you should be safe from having to test on all platforms, as you should be able to make non-visible changes later if necessary. But if you are using these directly and a large part of your application depends upon it, you may want to first build test programs for the different platforms and verify they work as advertised. In any case, if there is any question, you can and should test to find problems early if any suspicions arise.

While the MFC class support is not as extensive in embedded as the desktop, the classes that are supported in Windows CE-based devices have similar interfaces and behave the same. This also appears to be true for the Win32 API. This makes building portable applications much easier. Take advantage of MFC and Win32 in your programs, at least in the application and graphics layers. If there is a bug, Microsoft has many incentives to fix it, so you won't have to. And when Microsoft makes a behind-the-scenes improvement you may be the recipient of those improvements later without even realizing it.

Workarounds

Not everything will go as planned. You may run into a situation where you need to write code that you don't want to. For example: it's the night before your code releases to the quality assurance team. A program manager has just given you a last-minute requirements change at 6PM. You inspect your current design and code, and realize that you don't have the time to both re-architect your library in the manner you want and also implement and (reasonably) test your new feature. What do you do after you update your resume on your favorite job search engine?

  1. extern functions. These are not a very good approach, but they are quick for implementing some platform-specific code. Define the extern function in some middle layer, and implement it in all of the platform-specific application layers. The TicTacToe application used this approach during testing when the random number generator continually returned the same value.
  2. GetVersionEx. If this function is used at run-time, some version information can be used so that a decision can be made. Microsoft's online documentation for eVC3 does not recommend this method, however. They recommend using the next two approaches, if possible.
  3. GetSystemMetrics. This will return information about the platform and device, in particular monitor or LCD dimensions.
  4. LoadLibrary. This can be called with a named DLL, followed by a GetProcAddress call on LoadLibrary's return value, if non-null. If this returns a valid address, then a function can be called dynamically. It should be noted that ERROR_CALL_NOT_IMPLEMENTED may be returned on the dynamic function call if the function is only a stub. If you have enough time to create DLLs for all of the platforms then you should be able to guarantee that this will not fail at run-time. This appears to be Microsoft's preferred approach when handling platform-specific problems.

Conclusion

The TicTacToe application and sources included with this paper are just samples, while your code will probably be a real software product. It would be naïve to think being able to easily build a portable sample application implies that you can build your software using exactly the same methods with ease. For example, the TicTacToe code doesn't access a database, while much modern software does. How hard will it be to create a portable application that can access a SQL Server database? It would have to be tested to find out.

But the general ideas are the same. Building software with a layered approach is a good idea. Even if you run into a case where you can't reuse code for some new platform, what's the worst that could happen? You might have to write a completely separate application for this one device, while the others share most of the same code. This scenario really should not occur if very portable, layered code is written, however.

Don't think that it is a burden to write portable software applications that can run on any Microsoft platform, or at least Pocket PC and Windows CE .NET. It is actually a very entertaining exercise at the least, and it can be a very satisfying experience at most if the majority of the original design and code works out as planned.

Appendix 1

General description for building existing Microsoft Pocket PC MFC samples, supplied with eVC3, using eVC4.

  1. Open eVC4

  2. Select "File/New. . ."

  3. With "New" Dialog

    1. Select "Projects" tab

    2. Select "WCE MFC AppWizard (exe)"

    3. "Location:"

      Set to absolute path where new project parent directory will reside

    4. "Project name:"

      Insert exact same name of eVC3 project that is to be ported

    5. "CPUs:"

      Select all processors that project will be built against

      Recommendation:

      Select "Win32 (WCE emulator)" and "Win32 (WCE x86)" at least for desktop emulation

    6. Click "OK" button

  4. For each "WCE MFC AppWizard(exe)—Step*" Dialog do

    Accept defaults and click button that accepts input

  5. With "New Project Information" Dialog

    Click "OK" button

  6. Open Windows File Explorer

    1. Go to directory containing eVC3 Pocket PC Application project to port
    2. Copy all files in Pocket PC project directory to new WinCE.NET project directory just created by eVC4
    3. Important: just say "no" to overwriting any project file, for example—.vcp, .vcc or .vcw files
  7. Go back to eVC4 new project

    1. Select "Project/Add to Project/Files. . ."

    2. With "Insert Files into Project" Dialog

    3. Select all files in new project directory

    4. Click "OK" button

    5. With "Microsoft embedded Visual C++" Dialog (if it appears)

    6. Click "OK" button

      Note   Some files may already be included in the project; this is OK.

  8. Verify Settings

    1. "StandardSDK"
    2. "Win32 (WCE Emulator) Debug" (or "Release")
    3. "StandardSDK Emulator"
  9. Run "Build/Rebuild All"

  10. If project builds without errors

    In "STANDARDSDK—STANDARDSDK Emulator" Window

    Double-click "My Computer"

    Double-click ICON for new WinCE.NET application (same name as project)

  11. Else

    Make necessary changes until builds

Appendix 2

General description for building existing Microsoft Pocket PC Win32 samples, supplied with eVC3, using eVC4.

  1. Open eVC4

  2. Select "File/New. . ."

  3. With "New" Dialog

    1. Select "Projects" Tab

    2. Select "WCE Application"

    3. "Location:"

      Set to absolute path where new project parent directory will reside

    4. "Project name:"

      Insert exact same name of project that is to be ported

    5. "CPUs:"

      Select all CPU types you will build for

      Recommendation

      Add "Win32 (WCE x86)" and "Win32 (WCE Emulation)" for debugging and desktop emulation

    6. Click "OK" button

  4. With "WCE Application Step 1 of 1" Dialog

    1. Select "An empty project"
    2. Click "Finish" button
  5. With "New Project Information" Dialog

    Click "OK" button

  6. (New Project space should be created)

  7. With Windows File Explorer

    Select all files in Pocket PC application directory and copy to the new WinCE.NET mirrored application

    Important: just say "no" to overwriting project directories, for example—.vcp and .vcw!

  8. Back in eVC4 select "Project/Add to Project/Files. . ."

    With "Insert Files Into Project" Dialog

    Note   Current directory must be the current new WinCE.NET project directory.

    Select all files in Dialog

    Click "OK" button

  9. Verify that the following settings are correct for emulation

    1. Standard SDK
    2. Win32 (WCE Emulation) Debug
    3. Standard SDK Emulation
  10. Select the "File View" tab (left project window by default)

    1. Open "Header Files" virtual directory

    2. Double click "newres.h"

    3. In "newres.h"

    4. Comment out line

      #include "winver.h"
      
    5. (if it exists and save the file)

  11. Run "Build/Rebuild All"

    1. If it builds without error, in emulation window

    2. Double-click "My Computer"

    3. Double-click new application (same name as project) and run

      Else

      Fix any other errors in application

Appendix 3

Building the samples. eVC4 has been used as a sample. Instructions will be very similar for other Microsoft IDEs.

Building TicTacToeEngine

  1. Open eVC4

  2. Run "File\New"

    With "New" Dialog

  3. Select "Projects" tab

  4. Select "WCE Static Library"

  5. Set Location (anywhere you want)

  6. Project name:

  7. TicTacToeEngine

  8. CPUs

  9. Select (at least):

    Win32 (WCE Emulator)

    Win32 (WCE x86)

  10. Click "OK" button

    With "WCE Static Library—Step 1 of 1" Dialog

  11. Select all checkboxes

  12. Click "Finish" button

    With "New Project Information" Dialog

  13. Click "OK" button

  14. Open included source files

  15. Copy all TicTacToeEngine files to the new project directory just created

  16. Go back to eVC4

  17. Open "Project\Add to Project\Files

    With "Insert Files into Project" Dialog

  18. Select all files

  19. Click "OK" button

    With "Microsoft embedded Visual C++" Dialog

  20. Click "OK" button

    (stdafx already in project)

  21. Select "STANDARDSDK" and "STANDARDSDK Emulator" from build menu

    For (at least) each "Win32 (WCE emulator)*" build type

  22. Run "Build\Build TicTacToeEngine.lib"

  23. Run "File\Close Workspace"

    With "Microsoft embedded Visual C++" Dialog

  24. Click "Yes" button

TicTacToeGraphics

  1. Follow instructions for TicTacToeEngine up to building the project

  2. Replace "TicTacToeEngine" with "TicTacToeGraphics"

  3. Before building the project

  4. Run "Project\Settings"

    With "Project Settings" Dialog

    Settings for:

  5. Select "All Configurations"

  6. Select "C\C++" Tab

    Category:

  7. Select "Preprocessor"

    Additional include directories:

  8. <add absolute project directory for TicTacToeEngine, built above>

  9. Click "OK" Button

  10. Run same builds as TicTacToeEngine

  11. Close the workspace and all files like TicTacToeEngine

TicTacToe

  1. Open eVC4

  2. Run "File\Open Workspace"

    With "Open Workspace" Dialog

  3. Select and open the TicTacToe.vcw file from the included files' application\WindowsCE\TicTacToe directory

  4. Run "Project\Settings"

    With "Project Settings" Dialog

  5. Select "Settings for:"

  6. All configurations

  7. Select "C\C++" tab

    Category

  8. Select "Preprocessor"

  9. "Additional Include directories"

  10. <modify these settings as appropriate to your machine configuration>

  11. Select "Link" tab

    Category

  12. Select "Input"

  13. Foreach "Win32 (WCE emulator)*" (at least) in "Settings For:" do

  14. <modify these settings as appropriate to your machine configuration>

  15. Click "Ok" button

  16. Build and test the application in the emulator

References

[Lippman] Stanley B. Lippman, C++ Primer: Second Edition, Addison-Wesley Publishing Co., 1991. pp. 326-34.

To contact the author, e-mail Kirk Radeck.