March 10, 2003
Summary: Mike Hall takes a look at missing ordinals from coredll.dll and how to determine what's missing. He also discusses adding an MFC-based application to a Windows CE .NET operating system image. (10 printed pages)
Now that the RTM bits for the Microsoft® .NET Compact Framework are available for download, I thought it was about time I started writing some C# .NET Compact Framework applications. I really enjoy writing C# desktop applications, and wanted to get a feel for the development process using Microsoft® Windows® CE .NET. I had a fairly old version of Microsoft® Visual Studio .NET 2003 installed on my laptop (more on this later, since using the old version of the tools uncovered an interesting debug message in Platform Builder), and used this to build a fairly simple C# application. I wanted to build two operating system images: one that includes the final .NET Compact Framework components, and one that requires Visual Studio .NET 2003 to download and install the .NET Compact Framework components on my target device.
Rather than use the emulator, I've been using an SH4-based reference board to build and test C# applications. Don't get me wrong, the emulator is great, and I have been using this to test out my .NET Compact Framework applications, especially when on recent flights to the Windows Embedded Developers Conferences in Asia. (I doubt that the cabin crew would have been impressed with mini hubs, network cables, and reference boards being used on a flight.) I wanted to get a feel for how application development would be with a "real" board, and how similar the experience would be to using the emulator. So I deployed an application to a device that didn't have the .NET Compact Framework included. In this scenario, Visual Studio .NET 2003 will download and install the appropriate CAB files. The application failed to launch, and I got the following debug message in Platform Builder.
ERROR: function @ Ordinal 1172 missing in Module "coredll.dll"
Please Check your SYSGEN variable!!!
This is intriguing, as the same application deploys and launches just fine in the emulator. In fact, this is the first time I've seen such a message, so I figure it's time for some detective work. There must be a difference between the operating system running in the emulator and the operating system running on the reference board, but how to determine what's missing?
After thinking about this for a few seconds, the answer to this issue became somewhat obvious: The .NET Compact Framework requires a function that's not exposed from my version of coredll.dll, and this is ordinal 1172. (Boy, wouldn't a function name be useful here instead of an ordinal? This would immediately show me which component or technology is missing from my operating system image.)
If you've developed any Win32 code on the desktop, you will know that DLLs typically export their functions through a .DEF file, so all we need is the .DEF file for coredll. This is where we all say a big hoorah for the shared source that ships with Windows CE .NET. Take a look in this folder: C:\WINCE410\PRIVATE\WINCEOS\COREOS\CORE\DLL
There are a bunch of interesting files in this folder—perhaps apis.c is worth a look sometime in the future. But wait, we were going to take a look at coredll.def. Let's open up coredll.def in some appropriate editor, like Notepad, or some other such editor would be just fine; after all we're just looking for ordinal 1172 in the text file. So search for 1172... And there it is—SipGetInfo @ 1172.
; @CESYSGEN IF COREDLL_CORESIP SipStatus @1169 SipRegisterNotification @1170 SipShowIM @1171 ----------> SipGetInfo @1172 <---------- SipSetInfo @1173 SipEnumIM @1174 SipGetCurrentIM @1175 SipSetCurrentIM @1176 SipSetDefaultRect @1214 ; @CESYSGEN ENDIF
It would appear that the .NET Compact Framework required the SIP or Soft Input Panel. Adding this component to my platform resolved the issue.
Remember that I pointed out that I was running a very early build of Visual Studio .NET? After pinging the folks in the .NET Compact Framework team, I determined that RTM Compact Framework bits don't have the dependency on the Soft Input Panel, and once I'd installed a more recent build of Visual Studio .NET 2003, I could then deploy the .NET Compact Framework and my application without any issues (even though the operating system didn't have the SIP). That'll teach me to play with Beta products...
Actually, in some ways I'm quite pleased I saw this issue. This gave me the opportunity to find something out about Windows CE that I hadn't looked at before.
We typically run an "Ask the Experts" session at the Windows Embedded Developers Conferences. These are just great. Delegates get to ask any and all questions they have around developing for Windows Embedded. (Let's not forget Microsoft® Windows® XP Embedded here!). It can be fun to write code samples on the fly, to show how to do something, or to dive into the product documentation to show useful articles—not to mention to look at code samples you guys bring to the conferences. In many respects this feels much more like "Try to Stump the Expert." Anyhow, at the recent Windows Embedded Developers Conference in Beijing, China, a delegate was asking questions about developing MFC applications on Windows CE .NET. The final question was, "Okay, so once I've finished my application, how do I now get this application into my final operating system image?"
Now there's a good question. There are two parts to the answer. First, since this is MFC, we will need to include the MFC runtimes in our operating system. Does this sound familiar? It should. Remember that my .NET Compact Framework application wouldn't run because some of the required operating system components didn't exist in the operating system image. The second step is to modify BIB, DAT, and REG files to include the application and any associated files into the final operating system build.
To walk the steps needed to include an MFC application into a Windows CE .NET operating system image, I've built a simple "Release build" MFC Single Document application. Now we need to know which DLLs the application uses so that we can also make sure that these are included in the operating system. There are a couple of ways to do this. The first is to use Depends.exe (this ships with eMbedded Visual C++ 4.0), and the second is to use Dumpbin.exe (a command-line tool that ships with Windows CE .NET). Note that to use the command-line tool, you will need to ensure that your path is set up correctly. If you are working on a platform in Platform Builder, simply use Build | Open Build Release Directory, and the paths will all be set up okay. Trying to use Dumpbin from a regular CMD window will give the "Dumpbin is not recognized as an internal or external command" error.
Below is the output from Dumpbin when I look at the imports for my MFC-based application (command line is Dumpbin /imports MFCDemo.exe). We can see that the application needs mfcce400.dll and coredll.dll.
Microsoft (R) COFF/PE Dumper Version 6.24.2064 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file MFCDemo.exe File Type: EXECUTABLE IMAGE Section contains the following imports: mfcce400.dll 13028 Import Address Table 12630 Import Name Table 0 time date stamp 0 Index of first forwarder reference Ordinal 2074 Ordinal 1034 Ordinal 1351 Ordinal 2122 Ordinal 1150 Ordinal 1704 Ordinal 1941 Ordinal 2124 Ordinal 2117 Ordinal 2241 Ordinal 1254 Ordinal 837 Ordinal 1841 // NOTE: I've removed some of the listing // since this is quite longÃ‚Â… Ordinal 201 Ordinal 311 Ordinal 2103 Ordinal 1628 Ordinal 2247 Ordinal 1081 Ordinal 779 Ordinal 648 Ordinal 1097 Ordinal 1869 Ordinal 2588 8C ?messageMap@CWinApp@@1UAFX_MSGMAP@@B Ordinal 1908 Ordinal 2050 Ordinal 1910 COREDLL.dll 13000 Import Address Table 12608 Import Name Table 0 time date stamp 0 Index of first forwarder reference Ordinal 86 Ordinal 35 Ordinal 33 Ordinal 34 Ordinal 84 Ordinal 1645 Ordinal 287 Ordinal 267 Ordinal 36 Summary 1000 .data 1000 .rdata 2000 .rsrc 1000 .text
Okay, now I bet you are really curious to find out what the nine functions are that are imported from coredll.dll. Go on, admit it; I bet you are just itching to go take a look at coredll.def now that you know where it isÃ‚Â… Isn't it strange how the two issues of the .NET Compact Framework and including an MFC application into your device are somehow linked by the exported functions of coredll?
We now know that we must include mfcce400.dll and coredll.dll. MFC is a component in the catalog; we just need to locate it in the tree, and then add it to our platform. Note that this is only true of RELEASE applications. The debug version of MFC is not included in Platform Builder—why would you ship a device with a debug build of an application? The good news is that Microsoft® eMbedded Visual C++® will download mfcce400d.dll to your target if you're building and running a debug version of the application. MFC can be found here in the catalog: Catalog | Core OS | Display-based devices | Applications and Services development | Microsoft Foundation Classes (MFC). coredll must be present on all platforms.
The next step is to include the application into the operating system image. Again, we can do this in a number of ways. These include creating a custom .CEC file that copies my application to the current _FLATRELEASEDIR (build release directory from Platform Builder), and which also contains the appropriate BIB information. Alternatively, we could hand copy the MFC application to the build release directory and then modify the Project.bib, which will then add the application to the operating system image.
Time for a handy tip: One way to always copy a file to the build release folder is to drop it into this folder: C:\WINCE410\PUBLIC\<Project_Name>\WINCE410\<Platform_Name>\oak\files.
<Project_Name> is the name of your current Windows CE .NET project, and <Platform_Name> is the name of the current reference platform you are using. (In the case of using the emulator, this would be emulator.) I could therefore drop my MFC application into this folder, and this will be copied to the build release folder at build time. By the way, having the files in the build release folder doesn't mean they get included into the operating system image; this is controlled by Binary Image Builder (BIB) files.
Time for another handy tip: Excluding an application from your operating system image can be useful when you're debugging the application. Right-click on a User Feature in the catalog, and then click Settings. The following dialog will be displayed:
Figure 1. Including or excluding an application from a build
You have three options:
- Build and include in the operating system. This is the default option.
- Build and exclude from the operating system. This is useful if you want to debug and rebuild the application without needing to rebuild the operating system. You can use Target | Run Programs to get a list of available applications from your Build Release folder. This list will include applications that were both included in the operating system and applications that have been built but excluded from the operating system. You can then push the application to the running operating system, try it out, catch a bug, kill the application, recode, build, and push back to the device—kinda neat!
- Don't build, and exclude from the operating system. This is self-explanatory.
BIB files have two sections, Modules and Files. Modules are executable items, and Files are just that, files, bitmaps, sounds, documents and so forth.
Assuming we have an application called MyApp.exe, we would modify Project.bib as follows:
; ; Copyright (c) Microsoft Corporation. All rights reserved. ; ; ; Use of this source code is subject to the terms of the Microsoft end-user ; license agreement (EULA) under which you licensed this SOFTWARE PRODUCT. ; If you did not accept the terms of the EULA, you are not authorized to use ; this source code. For a copy of the EULA, please see the LICENSE.RTF on your ; install media. ; MODULES ; Name Path Memory Type ; -------------- --------------------------------------------- ----------- MyApp.exe $(_FLATRELEASEDIR)\MyApp.exe NK S FILES ; Name Path Memory Type ; -------------- --------------------------------------------- -----------
This will include MyApp.exe into the \windows folder on the device. You can, if needed, also remap the application to another folder on the device. You would use .dat files to make this happen. Perhaps this would be an interesting subject for a future article. Let me know if you'd like us to take a look at that.
We can see that MyApp.exe is included in the final operating system image both by looking at the build output window (see section below), and because we didn't get any build errors.
connpnl.cpl .text 814d3000 4096 1536 1127 o32_rva=00001000
connpnl.cpl .rsrc 814d4000 8192 5632 5284 o32_rva=00003000
stguil.cpl .text 814d6000 12288 11264 11222 o32_rva=00001000
stguil.cpl .rsrc 814d9000 12288 8704 8220 o32_rva=00005000
myapp.exe .text 814dc000 4096 3072 2856 o32_rva=00001000
myapp.exe .rdata 814dd000 4096 3072 2608 o32_rva=00002000
myapp.exe .rsrc 814de000 8192 7680 7564 o32_rva=00004000
memleak.exe .text 814e0000 4096 3072 2702 o32_rva=00001000
memleak.exe .rdata 814e1000 4096 512 380 o32_rva=00002000
dmatrans.dll .text 814e2000 8192 4608 4127 o32_rva=00001000
ceemulsrv.exe .text 814e4000 4096 2560 2106 o32_rva=00001000
ceemulsrv.exe .rdata 814e5000 4096 512 220 o32_rva=00002000
dc21x4.dll .text 814e6000 65536 65024 64617 o32_rva=00001000
ddi.dll .text 814f6000 110592 110080 109996 o32_rva=00001000
The other way of determining whether our application was included or not is to run the application.
Figure 2. MyApp.exe in the \Windows folder of my device
That's it for this month. We've already made a start on next month's article. Unfortunately, I can't tell you what we're writing about yet—don't you just love surprises?