Hodge Podge Lodge: Remote Debugging, Localization, and Globalization in Windows XP Embedded
February 18, 2003
Summary: Jon Fincher first delves into debugging issues with Windows XP Embedded runtimes, and then discusses localization and globalization topics in Windows XP and Windows XP Embedded. (11 printed pages)
It's time to pull up a chair around the cracker barrel and listen to me ramble on about Microsoft® Windows® XP Embedded again. For those of you keeping score at home, you may have noticed that my once monthly column appears to be on a bi-monthly trend. I seem to be having problems juggling all the new things that are happening here in Windows XP Embedded land. Hopefully, I'll have them resolved by next month's installment, which I hope to have for you next month…
This month, I'm going to talk about the linked concepts of debugging on Windows XP Embedded devices and localizing your images. But they're not related, you say. What's the connection? Simple. (Pay attention; there will be a quiz later.) Those are the two talks I delivered at our Devcon Taipei last month. I'll summarize the contents of those two talks for those of you who couldn't make it to any of our Devcons yet. If you want to hear them for yourself, you'll have to make reservations for the upcoming Devcon Europe in Munich, Germany next month.
Before we begin, let me extend a warm "Thank You" to everyone I met in Taipei last month. Although it was my third visit to your city, I still managed to find new things to do, new food to eat (I had fun trying to order at a local Cantonese restaurant where no one spoke English—fun because I don't speak Chinese!), and new places to see. There were new people to meet, and faces to match with names of people I've talked with on the newsgroups or in e-mail. It was quite a pleasure and honor. And one last word to my hosts who treated the American Microsoft staff to dinner Wednesday evening: gum bai!
Debugging on Windows XP Embedded Runtimes
Debugging applications and drivers can be a daunting task. I'm not going to be simplifying the task of debugging any, but will be simplifying the mechanics of setting up debuggers on Windows XP Embedded runtimes. The remote debugging capabilities of Microsoft development tools make it a rather simple thing to do. All it requires is a little setup on the device, and a little configuration on the debugging system. There are also some components and techniques that can make your job easier. The first step is configuring the runtime.
Assumptions and Definitions
There are two machines to think about when we talk about remote debugging: 1) the local development machine, where you will be writing and compiling your application, and 2) the remote device where the application will actually be running. For this discussion, the following assumptions are made about these systems.
- On the Local Development Machine:
- Microsoft® Windows® XP SP1.
- Windows XP Embedded with SP1, tools and repositories.
- Microsoft® Visual Studio® (version 6 or .NET).
- Windows Debugging tools (WINDBG, KD, and so on).
- Windows XP SP1 symbol files (*.PDB).
- Microsoft DDK (Driver Development Kit, optional).
- On the Remote Windows XP Embedded Device:
- Windows XP Embedded with SP1 image (with Remote management support and Networking support).
- Microsoft® Visual C++® Monitor (with additional files).
For the local development machine, the DDK is an optional application, but if you have it, you're sure to have the PDB files as well as the WinDBG debugger. The DDK (as well as the Debugging Tools and symbol files) are available, free of charge, from http://www.microsoft.com/ddk/.
There is one thing that you might need to add on the Windows XP Embedded device, and that is support for the Visual C++ Monitor. It's an easy thing to add to a runtime, either while running or before deployment. It's easy enough to componentize as well, assuming you already have Visual Studio.
For our demonstrations, I started with a minimal configuration (just to show that this works with a small footprint) with WinLogon. I then added the following components:
- Software : System : Management : Applications : Telnet Server
- Software : System : Management : Applications : Event Log
- Software : System : Security : Infrastructure : Automatic Logon
- Software : System : System Services : Base : Remote Registry Service
Telnet Server is unnecessary unless you are debugging on a headless device. Event Log is something you don't want to debug without, as it allows you to inspect any errors that are thrown by the applications you're running. Automatic Logon makes sure the device boots directly to your shell. Again, this is necessary for headless devices, but not as crucial for devices with video and keyboard. Remote Registry Service allows you to remotely inspect and modify the registry on a network-connected device.
Before we build the configuration, there are a few properties we need to set. Find the Computer component in your configuration (Standard PC, Advanced Configuration, Power Interface PC, and so on), and click Settings under it. Under System Identification, click Show and name the device—if you don't, First Boot Agent (FBA) will assign a random name to the device, and your chances of finding it on the network are closer to zero than you want them to be. For our demos, we named the device "XPE-DEVICE". Clever, eh?
Next, find the Administrator Account component, and click Advanced in the details pane. In the Extended Properties dialog, select cmiUserPassword and then click Edit. Change this entry to something that's not blank—it doesn't matter what, just as long as it's not empty. Once that's done, click OK twice to get back to the Configuration Editor, and then find the Automatic Logon component. Click Settings under that component and set the User Name to "administrator." Set the Password to the value of cmiUserPassword you set in the Administrator Account component above. Now your device will automagically log on as the Administrator—after you build and deploy it, of course.
Once the device has been booted and gone through FBA fully, it should be sitting in your shell. Make sure you've got everything setup properly by opening a command prompt on the development machine, and entering the following command:
If you get responses from the machine, it's up and ready for you to finish the configuration.
Visual Studio Remote Debugging
The first thing we'll cover is debugging a Visual Studio project remotely. There are a few things that need to be setup on the device before Visual Studio can successfully debug an application remotely.
First, on your development machine, from the command prompt, enter the following command:
net use Z: \\xpe-device\c$
When prompted for the username and password, enter "administrator"; then enter the password you provided above. This creates a share to the root of the device's boot drive, and sets up a trust relationship between the two machines, enabling other network services to connect unhindered between the two. This is an important step. The share itself is useful, but the trust relationship is crucial. Without it, remote debugging won't work.
Now you can install the Visual C++ Monitor on the device. Well, maybe install is too strong a word—copy the files is more accurate. From your development machine, create a directory called Z:\Remote (remember Z: is a share on the device). Now, go to the folder: \Program Files\Microsoft Visual Studio .Net\Common7\Packages\Debugger, and copy the following files to Z:\Remote:
Now, one thing to note: When I was setting up my demo machines for the talk in Taipei, I couldn't find all those files on my development machine. I managed to find MSVCR70.DLL, NATDBGDM.DLL, NATDBGTLNET.DLL, and MSVCMON.EXE. The others were nowhere to be found. I've no clue what they do, but I do know my demo worked just fine without them.
Now we can start Visual C++ Monitor on the device. If you've got a shell on the device, start it from there. If you're running a headless device, Telnet into the device and start MSVCMON that way. In either case, the command line to use is:
This allows any debugging session to connect to the device to deploy and debug applications.
Now you can start Visual Studio on the development machine. For our demo, we actually based the entire application on the Z: drive (mapped to the C:\ drive on the device), and built and deployed the application there. You can target the application locally if you want. In either case, once the application has been created (or if you're using one that's already been created), right-click on the solution in Solutions Explorer and click Properties. On the Properties dialog, click Debugging. You want to modify the following settings:
- Connection: Remote through TCP/IP.
- Remote Machine: XPE-DEVICE (or whatever you named the device).
- Remote Command: The command to run your application as it appears on the device (this should be something like C:\solution\debug\app.exe).
These settings tell Visual Studio where to put your application, what machine to connect to, and how to run the application once it's on the remote machine. Now you can build, execute, and debug the application from Visual Studio. Use whatever debugging techniques you're used to—they all work, including breakpoints, conditional breakpoints, watch variables, call stacks, and so on.
For those of you who haven't tried it yet, or don't know what this implies, let me explain. The settings we tweaked above tell Visual Studio how to run an application on your device. Visual Studio, however, isn't running on your device—Visual C++ Monitor is. The Remote Machine tells Visual Studio what machine to talk to, and it passes the Remote Command to it. When you build the application, you put it on the remote device, and when you execute or debug it, Visual Studio tells Visual C++ Monitor to execute the application, which sets up the passing of debug commands back and forth between the two. Very cool.
These techniques work well for C and C++ code. They did not work for me, however, when I tried it with C# code (yes, I'm a convert—I love C#). I was pressed for time to get the demo working, so I never investigated why it didn't work. I just dropped back to a C++ application. If this is important to you, let me know and I'll find out why. Or if you know why, let me know; newsgroups are our friend here.
Additional Tools and Techniques
There are some additional tools that make debugging and tweaking your device easy. Now that a trust relationship has been set up between your development machine and the Windows XP Embedded device, you can use Remote Registry editing to modify the registry on the device without RegEdit needing to be installed. On your development machine, open RegEdit. From the File menu, click Connect to Network Registry, and enter the name of the device. Click OK, and you should be looking at selected registry hives from the device. This technique limits your registry editing to the HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER hives, but that's better than nothing.
You can also use Remote Computer Management to perform the same management tasks on the device as you would on your desktop from a remote location. Right-click My Computer on your development machine's desktop, and click Manage. Right-click Computer Management in the tree, and click Connect to another computer. Again, enter the name of the device, and click OK. You should have complete remote management control over the device, including adding and removing users, starting and stopping services, viewing the event log, and inspecting system settings.
Kernel Debugging… In the Study… with a Keyboard
Application debugging is a good thing to have, but what if you're debugging a driver? Visual Studio remote debugging won't work, as it's strictly tailored for applications—Ring 3 specifically. That's where the kernel debugger comes in.
Kernel debugging has been built into every Window NT operating system. There are some key things you need in order to utilize this feature, namely, the debugging client and symbol files. You can get both from http://www.microsoft.com/ddk/debugging, and you can generate symbols for your driver during compile.
There are a few terms that I should define here. The target computer (or host computer) refers to the machine that we are going to debug. In our examples, this refers to a Windows XP Embedded device that has the kernel debugger enabled on it. The remote computer refers to the machine that is running the debugger client. It is connected physically to the target device and controls the target through the debug interface.
The first thing you need to do to successfully start a kernel debugging session is tell Windows to start with the debugger running. This is done in the BOOT.INI file. You can do this for Windows XP Embedded runtimes in the BOOT.INI file after the runtime has been generated. You can even change the setting post-FBA. Whether you're enabling the debugger on a Windows XP Embedded runtime, or on a full desktop installation, the sequence is the same. Open BOOT.INI in a text editor. You should see something similar to what's below:
[boot loader] timeout=1 default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS [operating systems] multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Windows XP Embedded" /fastdetect
Note If you're running on a SCSI system, the
multi(0)entries will be
This is a normal BOOT.INI. To enable the debugger, modify it so it appears as follows:
[boot loader] timeout=1 default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS [operating systems] multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Windows XP Embedded" /fastdetect multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Windows XP Embedded" /debug /debugport=com1 /baudrate-115200
In this case, I copied the last line, removed the /fastdetect switch, and added some debug switches. These three new switches tell Windows XP to start with the debugger enabled on COM1 with a speed of 115Kbps. You can change the COM port and baud rate to suit your needs, and you can even specify a 1394 port to use for debugging. (See the "Using Debugging Tools for Windows" help file installed with the debugging tools on how to set this up.)
Once the target system has been configured to start the kernel debugger, you need to set up the client on the remote computer. The easiest way to do this is to set up a batch file that automatically sets the correct environment for the debugger and launches it. Such a batch file would look like this:
@echo off set _NT_DEBUG_PORT=COM1 set _NT_DEBUG_BAUD_RATE=115200 set _NT_SYMBOL_PATH=C:\sym C: cd c:\debuggers start windbg -k
This batch file sets up three environment variables for the COM port, baud rate, and symbol path. The baud rate setting is the important one. Make sure it's the same as what was set in the BOOT.INI on the target device. You may need to change the symbol path and debugger folder to conform to your installation.
Note You don't need to do this in a batch file; you can start WinDBG and modify these settings interactively. This batch file is easier and more consistent for frequent debugging sessions.
Now for the last and most important part—the physical connection between the two machines. As you may have surmised, the kernel debugger uses COM or 1394 ports to communicate between the target and the remote machines. You need to connect the two machines using a null modem cable. This is simply a serial cable with the send and receive lines crossed in the middle; send on one end goes to receive on the other. This allows the two machines to talk to one another without using a modem. You can get these cables (sometimes called debug cables) at any computer store.
To start debugging, run the batch file on the remote computer to start the kernel debugger. When it is ready, the last viewable line will read, "Waiting to reconnect..." Now boot the target device, and notice the boot menu now has two entries—one for your embedded operating system (OS), and a second embedded OS option marked "(debug)." Select the "Windows XP Embedded (debug)" option to boot into the debugger. As the device boots, watch the WinDBG window on the remote machine. You'll see it loading extension DLLs, followed by a connection confirmation. At this point, you're debugging.
Additional Uses for the Kernel Debugger
The kernel debugger can also be used to allow application debugging. This can be helpful if you're debugging something outside the Visual Studio environment. To do this, you'll need to make sure NTSD.EXE is on your Windows XP Embedded device. NTSD.EXE isn't a part of any component, but you can componentize it yourself. Make sure you include DBGENG.DLL in the file resources when you do. To debug an application, you'll start the device in the debugger, and then execute the following:
ntsd –d <application>
This tells NTSD to pipe all its output to the kernel debugger, allowing you to control the application under the kernel debugger on the remote machine. There are more options to NTSD; enter NTSD /? for a complete list.
I also won't go deep into how to use the kernel debugger here. It is well beyond the limits of this column (and my abilities) to describe the subtle nuances of kernel debugging. For more information on the debugger, check the help files and http://www.microsoft.com/ddk/.
Localization and Globalization
So what does all this talk about debugging have to do with localization and globalization? Nothing! If you read the beginning of this article, you'd know the only connection between them is that they were both presentations given at Devcon, both in Las Vegas and Asia. (Told you there'd be a quiz later.)
Note Most of the features described here are implemented in Windows XP, and therefore are inherited by Windows XP Embedded. I'll call out specific features to Windows XP Embedded when they come up, but know that when I say "Windows XP provides...", it also means that support is available in Windows XP Embedded as well.
Localization and globalization are two separate but highly interconnected topics. Localization deals with adapting the UI of your application to meet the language, cultural, and political expectations of a given geographical location. Globalization deals with the broader topic of designing applications and operating systems to accommodate any geographical location they may be running in.
The basic architecture of Windows XP (and therefore, Windows XP Embedded as well) lends itself well to internationalization. At the Executive API level and below, all strings are encoded in Unicode. Unicode-based applications communicate directly to the Executive API in Unicode, while non-Unicode applications enter through a translation layer (transparent to the application itself) at a higher level in the Win32 subsystem. Since everything under the hood is done in Unicode, any textual information passed in any language encoded in Unicode can be handled and processed natively.
Windows XP also supports a number of services to support different ways of entering textual information. Multiple keyboard layouts and Input Method Editor (IME) services allow direct typing in a variety of languages. A framework of text services also supports speech and handwriting recognition in different languages. Code page support for 16-bit ANSI applications provides backwards compatibility. The National Language Support (NLS) API provides controlled, consistent access to locale information such as time and date formats, number and currency formats, and text sorting orders.
There are also different ways to support textual output of information. The OpenType Font (OTF) support in Windows XP allows text output in different languages and in a variety of open typefaces. Uniscribe provides complete support for scripting, including bi-directional text (Hebrew and Arabic are two examples of right-to-left text), contextual shaping (forming glyphs differently based on their context in the word), special word-breaking and hyphenation rules, and combining characters.
Because the architecture of Windows XP is open to any type of Unicode encoded text, we have the capability of mixing and matching languages in the same application. If you've pointed your English version of Microsoft® Internet Explorer at a Japanese Web site and been prompted to install the Japanese language pack, you've seen this in action. IMEs for different languages can be installed on the English Windows XP version to enable bilingual text entry. One of my colleagues does this, adding a Chinese IME to his English Windows XP desktop to enable him to write documents in both English and Chinese. He can even run Chinese versions of software on his English Windows XP desktop without causing problems. (Actually, so could I, but as I mentioned before, my Chinese is limited to saying "hello" (ni how), "thank you" (xie xie), and "bottoms up!" (gum bai!))
So, if the underlying APIs of Windows XP don't care about what language you use, what is actually different in a localized version of Windows XP? Surprisingly little. There is additional locale information to support the geographical region, customized setup information to allow localized installation of the OS, and geography-specific device drivers. The only binaries that are recompiled for localized OS versions are the setup routines, OS loader, and 16-bit support subsystem. We build local Windows XP version off the same source as we build the U.S. English versions. The practical upshot of this whole thing is that we have been able, with the exceptions listed above, to separate the functionality of Windows XP from the user interface. No matter which localized version you have, the fundamental operations are the same (they're the same bits!). Only the presentation is different.
What this separation of functionality from UI allows us to do is to switch the UI to a localized version dynamically. This capability is encompassed in the Multilingual User Interface, or MUI. The MUI allows the end-user to select the language they want Windows XP to present to them, and to switch to a different language if they choose. This is done by keeping localized UI resources available on the system for the user to select. How does this work?
In a single language situation, applications keep their resources in the executable itself or in a DLL. Requesting a resource in the application means a call through Win32, which winds up in NTDLL.DLL. NTDLL.DLL locates and loads the resource from the specified resource file and passes a handle to it back up the application.
Using the MUI, the request path is the same, until NTDLL.DLL gets involved. It checks the resource language setting against the setting the user has set. If they are different, it locates an alternate resource in a well-known location. A handle to the localized resource is then passed back to the application. All of this is completely transparent to the application.
One of the big benefits of using the MUI is that localization occurs on a per user basis. Two users on the same machine can select different languages to use. The same underlying binaries are used, which means that QFEs and Service Packs for English Windows XP will work and can be installed on localized or MUI systems. Also, this means that there are fewer different versions of the OS to maintain and administer.
As I mentioned at the beginning of this section, all of this architecture is present in Windows XP, which means Windows XP Embedded inherits all this, and then some. Windows XP Embedded allows device builders the opportunity to install only those languages they will need on their device, and only those portions of language support that make sense. For example, machines with no keyboard input have little reason to install a keyboard layout or an IME. Supporting different languages on Windows XP Embedded is made easy by our Language Support components.
Language Support Components
Language Support components bring together into one place all the pieces needed to support a given language. This includes fonts, keyboard layouts, and code pages. These components also provide configuration options for tailoring the language support to specific geographic regions. For example, the English Language Support component can be set up for the U.S., Great Britain, Canada, Australia, and other countries, each of which has slightly different keyboard layout and font information to support the location. The settings also help tailor locale information for all locales using that language. All told, Windows XP Embedded has components to support 23 different languages, including English.
While the Language Support components help tailor locale-specific information, the real meat of locales is in the Regional and Language Settings component. This component allows you to configure the runtime to use specific locale information—standard formats, text sorting, specific code-page settings, geographical information, and basic language settings. It detects and reacts to different Language Support components to present only those options that make sense for the languages specified. For example, if you've selected the German Language Support component, you will not be able to select "U.S. English" as the default language setting. The settings you make here are default for all user accounts on the system. They can be changed at runtime, but not in Target Designer.
By the way, these language support components, along with other localization components, can be found in Software : System : International : Infrastructure. This category also includes the various IME components.
Language support is one thing; localizing the entire operating system is another. As mentioned above, Windows XP implements the MUI concept, separating UI from functionality to allow users to localize the operating system to their tastes on the fly. Windows XP Embedded also uses the MUIs for the same reason, and we've componentized the MUIs to make localization easy. MUI components are available for Windows XP Embedded with SP1 for download (more on that later) or on CD. They need to be imported into the database before they will work. Two caveats to mention here: When importing, make sure the "Copy repository files to repository root" is checked, or none of the localized MUI files will be available in your configurations. Also, make sure you have the Repositories share on your database machine set up for read/write access. If not, you'll find that future MUI imports will fail.
To use the MUI components, start with a regular English configuration, built and tested. This helps narrow down any possible problems you may be having, isolating them to the MUI or to the base configuration. Then, import the languages you want to support and add them to your configuration. The Language Support and Regional and Language Settings components will detect and work with instantiated MUI components in your configuration, so you'll want to double-check or adjust their settings before completing your build.
Two caveats are worth mentioning here: First, in the Language Support component, there is a check box titled Include multilanguage user interface resources. Make sure it's checked. If it's not enabled, remove the Language Support component, and add it back in. The check box is enabled when it's added to the configuration. Secondly, if you want to be able to switch languages dynamically in the runtime, you'll want to check the Support all system locales for <language> check box. Once you've reconfigured the language settings, you can check all dependencies, rebuild, redeploy, and test.
And if the MUI packs on the CD aren't enough for you, we've released 22 new MUIs on the Web for Windows XP Embedded with SP1. Go to the Windows Embedded home page for details, and make sure you've got a fast connection. MUI packs are big, averaging 75 megabytes per language. You don't want to be downloading them on a 19.2 Kbps dial-up line, unless you've got a good book to read.
We've discussed the mechanics of setting up remote debugging on Windows XP Embedded runtimes, including debugging applications through Visual Studio remote debugging, and kernel debugging for drivers. Both of these techniques are necessary for complete verification of embedded systems using Windows XP Embedded. While you can test both your applications and device drivers on desktop systems running Windows XP, final verification requires testing on the actual embedded device. Problems found need to be debugged on those devices, and these techniques give you the tools to do just that.
We've also discussed the basics of localization and globalization, introduced the Language Support components in Windows XP Embedded, and gone over the basics of MUIs. For devices that will be sold and used throughout the world, the architecture supporting multiple languages on Windows XP makes localizing the operating system and custom applications very easy. Windows XP Embedded inherits the full localization capabilities of Windows XP, including support for locales, alternate keyboard layouts, and complete text output support. With the introduction of MUI packs for Windows XP Embedded, localizing the operating system is now a simple and user-selectable operation.
As for next month's column, I have no idea. We'll see when it gets here, although I am looking forward to visiting Munich again for Devcon Europe. See you there!