Component Designer: Casting the Mold, Part 1
January 15, 2002
Welcome back! The holidays have passed in the U.S., and I'm back, reasonably refreshed, and ready to get started dissecting the first of our Microsoft® Windows® XP Embedded tools, Component Designer. I'm hoping you're ready as well. Why Component Designer first? Well, it's like this…
One of the strong points about Windows XP Embedded is the development cycle. You can start developing for Windows XP Embedded without even having the tools! In fact, our development cycle for Windows XP Embedded can be found in the Concepts Guide or in the product documentation. For completeness sake, I'll repeat it here:
- Identify the hardware on your target device.
- Choose the features and functionality required in your run-time image.
- Identify the embedded system-specific features that need to be included in your target device.
- Include your components.
- Build your run-time image.
- Deploy your run-time image.
Note that the first mention of our tools occurs around step 3—the tools aren't actually used until step 4. The groundwork in steps 1 and 2 are where you begin, by identifying the hardware, and by defining features and functionality. These features and functionality may include your own applications, or third-party applications.
But how do you develop for Windows XP Embedded when you don't even have the tools or a runtime on which to test? Simple—develop on Windows XP. Since the binaries for Windows XP Embedded are the same as for Windows XP, anything that runs on Windows XP will run on Windows XP Embedded. You can do your full develop-test cycle on Windows XP, and then package your application as a component for use in Windows XP Embedded.
Note While I use the term "application" in this document, the process is equally applicable to device drivers and system services.
Components and Componentization
Why should you even use Component Designer? I mean, if Windows XP Embedded can run anything that will run on Windows XP, then why don't I just create an install program, and install it? That can work—as long as your run-time image contains all the support DLLs necessary to run the installer, and you're running on R/W media, and you've got enough media space to handle the temporary files, and you've got enough memory and pagefile to handle the process. Since most embedded devices can't meet all these requirements, we need another way to put that functionality into a runtime. That's where components come in.
Components are easily defined: They are the smallest individually selectable pieces of functionality that can be included or excluded from an embedded run-time image, and are comprised of files, registry entries, and dependency information. In short, a component is a block of functionality. Windows XP Embedded comes with a database full of components—they're the most basic element in your configuration. The process of turning your application into a component is called, oddly enough, componentization (mainly because computer guys love to turn nouns into verbs by adding the "-ize" suffix). And the tool used to componentize your application is called Component Designer.
Remember I said that we want to avoid running install routines on Windows XP Embedded runtimes? That means we have to figure out what the installer does, and make sure we can do it as well. Most installers do three things:
- Copy files from a flat to a final location.
- Create registry keys based on install options, user input, or environment.
- Register COM objects and DLLs.
In order for Windows XP Embedded to accomplish these, we need to know a few things:
- The files in your application.
- The registry keys used by your application.
- Any files not part of your application that need to run properly (such as runtime libraries, existing system services, and so on.)
- Any DLLs that need to be registered.
- Anything that requires user input or analysis of the run-time environment
We'll delve into parts one and two today—parts three, four, and five (and more) will be covered next month. There are a few other things that we need to know, but we'll get to these as we move forward.
The files and registry entries in a component are called resources. Files required to make your application work are called file dependencies. The files in your application should be relatively easy to find—you built them, after all! The registry keys might be a bit tougher to find, but still should be relatively easy. The file dependencies, however, may take a bit more doing. And what if you're componentizing a third-party application for which you don't have source code? What then?
Discovering resources for third-party applications, and discovering file dependencies are very similar. Without source code, it's difficult to know what, if any, third-party DLLs you are calling into. There exist today tools that can monitor and report the file and registry key accesses made by an application. These tools can be invaluable for discovering what file dependencies your application has. There are also tools that can compare system snapshots, and report the differences both before and after file installations. Using these tools to monitor the installation of applications should give you a good start on the file and registry resources of that application. And with that data in hand, you can start using Component Designer.
Defining a Component
When you start Component Designer, you'll notice the screen is blank. Component Designer allows you to have any number of components open and working at one time. Create a new component by selecting File, and then New. This will create a new SLD (Source Level Definition) file for you, in which to begin creating your component. (More on SLD files as we continue.)
The first thing you'll notice is a tree view that appears on the left side of the screen, with two entries—your new SLD (named New Document 1), and a platform (in this case, Windows XP Embedded Client x86, our only current platform). In the future, when more platforms are added, you will have to select which platform your component is designed for. This is an architectural change from Windows NT Embedded 4.0, where the component you selected meant the difference between a Workstation and a Server machine.
Expand the platform node, and you'll see a number of entries under it—Components, Repositories, Dependencies, Packages, and Repository Sets. We'll deal with the Components and Repositories entries this month, and cover the rest of them next month.
Right-click on the Components branch in the tree, and select Add Component. This will create a New Component 1 branch. Click that to see the basic component properties, which appear in the right pane of the window. Note that you can add as many components to your SLD file as you want. Therefore, if you have a set of two or more related components, you can put them in the same SLD file, and when you import that file into the database, they'll all be added at once.
The basic component properties include such things as Component Name, Description, Version, Author, Owner, Vendor, and Copyright. These basic properties are what users of your component will see in Target Designer. All of them are free-form text fields—fill these basic properties in as desired for your component. You'll also notice three grayed-out fields called Revision, Date Created, and Date Modified; Component Designer handles these fields itself. The date fields are self-explanatory. But what about the Revision field?
Every time you save a SLD file, Component Designer increments the Revision field. This field is used by Target Designer to discern between different released versions of the same component during upgrade operations (we'll discuss releasing a component further down, and upgrading during the Target Designer article). In short, it's a form of version control, built into the architecture.
There is also a drop-down control, Build Type, which is used to control release and debug versions of your component. When you build a configuration in Target Designer, you can select whether you want to build a release or a debug runtime. That flag is used to select which components are used, based on the flag setting here.
Probably the most important aspect of defining a component is encapsulating the files that make up that component. There are two steps to this process: First, define the repository the files will live in, and then tell the component what files are needed and where they go.
Defining the repository is very easy. Simply right-click the Repositories node in the tree view, and select Add Repository. You'll see the basic properties appear in the right-hand pane. Notice they're very similar to the basic component properties. That's a function of the object-oriented design of the system I discussed previously—all objects have a standard set of properties that define them.
The crucial part of defining a repository is telling it where the files are. This is done in the second part of the details pane. Click on Browse next to the Source Path field to browse to the folder containing the files for your application. The Source Path will be populated with the relative path to your files.
There are a few points to mention here. Since the source path is a relative path from the location of the SLD, it's beneficial to put your application binaries in a subfolder under the folder your SLD lives in. All my SLDs have a .\Rep folder under them to hold the files. Also, all repositories are flat—there are no subfolders under repository folders. Therefore, your Source Path folder should be flat as well. If you have naming conflicts, you should rename one of the files to a unique name. Don't worry; when you define the file resources for the component, you can specify both the source and destination names for the file. This is also a good idea for release and debug components—they can live in the same repository, as long as you decorate one set of names.
I know what you're asking now: What happens to the repository folder? We'll get into more detail when we tackle Component Database Manager, but the simple story is that a new repository folder is created on the database server machine, and the files from your Source Path folder are copied into it. When we need the files to build a runtime, we go to the database server, find the repository folder, and copy the files to their final locations as defined in the component.
Defining File Resources
So, we've got a repository containing our files; now we need to make sure the component knows which repository to use. Click the component node in the tree, and find the Repository field in the details pane. Click Repositories next to it to bring up the Select Repository dialog. You can pick from any repositories that are already in the database, or are defined in the components you are editing.
Note that this process only tells the system where to find the files, not what files to use. We do that in the component itself.
Expand the component node in the tree—you'll see a number of entries under the component. Right now, we're concerned with the Files node. Right-click the Files node, then select Add, then select File. You will see the Add File dialog.
The Add File dialog presents another set of properties for each file we want to define in our component. Target Name is the final name of the file when it's copied to the runtime. Source Name is what that file is called in the repository. Description is a free-form text field you can use to help document your component. Destination is the path on the runtime into which the file should be copied. You can click the arrow button next to the Destination field to pick from a standard list of destinations, or type your own. Check the Folder Only check box if you simply want to create a folder (no need to do this to put files in a new folder—Target Designer is smart enough to do that).
When you've selected a Destination and a Target name, the Effective Path field will be filled in with where Component Designer thinks the file would go on the development machine—a good double check for you. And, as always, select the Release and Debug check boxes under Applicable Build Types to control when bits are built by Target Designer. Once all fields are filled in, click OK to accept and close the dialog, or Apply to accept the changes and continue adding files.
As you may have seen, when you right-click Files and select Add, you can also select Add Multiple Files, or Add All in Folder. These are shortcuts that can help with bulk data entry while sacrificing control. They can be very useful if the files you are adding to your component are already installed in the correct locations on your development machine. Remember, you can always double-click a file resource to bring up the Add File dialog and modify the specific properties as necessary.
Defining Registry Resources
Defining registry resources is much the same as defining file resources. Right-click the Registry Data tree node, select Add, then Registry Data to bring up the Add Component Registry Data dialog. If your registry data is in the registry on your development machine, you can select Add, then Registry Branch, to import the entire registry branch at one time. Double-clicking any registry resource will bring up the Add Component Registry Data dialog.
This dialog can be confusing at first glance, but it isn't very difficult to use once you know how. At the top, we can select the root hive we want to put our data into. Directly under it, in Key Name, we put the remainder of the registry key path. We can also click Browse to browse the current registry for a key. If we want to simply create a registry key, we can check Key Only. However, the registry gets interesting when values and data are added. Value Name is rather self-explanatory, and when a Root, Key Name, and Value Name are populated, the Registry path field shows where the data will eventually go. As always, at the bottom, you will find the ubiquitous build type selectors and the Description field.
Registry data types can be confusing for beginners. Here's a quick rule of thumb: Don't use a data type unless you know it is specifically needed. All registry data type definitions can be found in the Windows XP DDK documentation, as well as on MSDN and in the Knowledge Base, but we'll define a few here. REG_DWORD is a simple double-word (4 bytes) integer value. REG_SZ is a zero-terminated string (we handle the zero-termination). REG_MULTI_SZ is a special string type for holding multiple strings at once, while REG_BINARY is a free-form binary data field.
Note The Add Component Registry Data dialog is a powerful tool for defining registry keys and values almost anywhere in the registry. Remember that randomly or haphazardly creating registry keys, values, and data types can lead to no boot situations.
Save, Save, Save!
As with any development environment, the key to creating lasting impressions, reducing work load, and improving individual morale is to save your work. But what happens when you save an SLD?
To answer that, we need to know what an SLD really is: It's nothing more than a text file. For those of you who have used Windows NT Embedded 4.0, that's a relief, I'm sure. Now, the bad news for you: It's an XML file. Don't believe me? Save your SLD now and open it in Notepad. Go ahead, I'll wait.
See. Told ya.
But why use XML? The architecture of Windows XP Embedded, as well as Windows NT Embedded 4.0, revolves around a database holding components. In Windows NT Embedded 4.0, that database was Jet based, and held not only components, but configurations as well. In Windows XP Embedded, the database is SQL based, and holds components only. What better way to hold structured data than in a file format designed to handle structured data?
If you did our little exercise above, you'll have noticed a number of extra things in the XML file that we never defined. Two of them are very important to understand, even if you never see or use them—the VSGUID and the VIGUID.
GUID Rhymes with Squid… or is it Fluid?
GUID stands for Globally Unique Identifier (and can be pronounced either way). Anyone who's done any COM programming will recognize GUIDs—every COM interface is identified at the system level by one. They're 128-bit pseudo-random numbers guaranteed to be unique on any machine anywhere. I did the math one time—if you generate one GUID per second, you'd have generated them all in something like 170,000 years. Pretty good guarantee.
So why do we use them? For the same reason COM uses GUIDs—to uniquely identify objects. It's too easy for two components to have the same name. Using GUIDs as the identifier, every component can be unique.
But why did we use two different GUIDs for each component? Well, it might help to know that VSGUID stands for Version Specific GUID, and VIGUID for Version Independent GUID. Every component gets a VIGUID, and all different revisions of that component share the same VIGUID. However, when you release a component (next month, I promise), the VSGUID changes. This allows our tools to identify all different revisions of a given component (using the VIGUID), and select different versions for use (using the VSGUID). And using the Revision field I mentioned earlier, we know what order they were created in, so we know which one came first, and which is the most recent—which allows us to upgrade an older revision with the most recent revision.
And guess what—almost every object in Windows XP Embedded has a GUID associated with it. Components, repositories, packages, repository sets—all have GUIDs to uniquely identify them. The caveat here is that even if two objects have the same name, if they have different GUIDs, they're unique. For example, if you define a repository in two SLDs, each called "My Files," they'll both be unique, because they have different GUIDs. Be aware that under the hood, Windows XP Embedded uses GUIDs rather than names to identify all objects.
So what have we discussed today? We glanced through the recommended development cycle to get our bearings, and then defined a component and the componentization process. The tool for componentizing your application is Component Designer, and we discussed some of the basic features of Component Designer. We delved into some architecture discussion to explain the concepts of components, repositories, file and registry resources, VSGUIDs, and VIGUIDs. We discussed the basic properties of components, and their similarity to the basic properties of other objects. We also showed that the container file for components, SLD files, are nothing more than text files in a standard XML format.
So, what's next? Well, next month, we'll discuss the remaining properties of a component, as well as more advanced resources. We'll cover component, group, and build-order dependencies, as well as group memberships. We'll also tackle the last three objects that can live in a SLD—dependencies, packages, and repository sets. And as we go along, I'll pass on architecture information, caveats, and hints. Hope to see you next month!