First Boot Agent: Not Just a Pretty Face
May 21, 2002
Welcome back to the column! I need to apologize for missing last month. I could offer you excuses involving national security and international intrigue, or possibly the whims and whimsy of minor demigods who got in the way, but this is supposed to be a technical column, not creative fiction. In any case, I'm back this month, so let's get to some information.
FBA: Simulating Setup
Okay, you've got your application or driver componentized, including all the file and registry resources. Now you need to register a COM object that your application uses and ships, or set up service data for your device driver. One of the tricks to componentizing an application or driver is simulating dynamic setup process data. Moving files and registry keys around is easy enough to do using file and registry resources in the component, but doing things like registering DLLs and COM controls, installing service data, and setting dynamic data is a bit tougher. This is where First Boot Agent, or FBA comes in.
First Boot Agent is a set of processes that run on the Microsoft® Windows® XP Embedded runtime during its first boot. First Boot Agent (also know as FBA) reads and executes instructions placed in a special place in the registry. These instructions are populated by individual components, and can specify a number of different actions, including DLL registration, special data handing, service data installation, and other things. When FBA has finished processing everything, it cleans itself up and reboots the machine. Subsequent boots of the Windows XP Embedded runtime will not execute the FBA instructions again. FBA is a one-time operation, and usually happens on a golden master device before replication.
So what can FBA do for us? There are eight FBA directives we can specify. Two of them do nothing but populate the registry with crucial device data; these are the Service Data and PnP Device ID directives. One sets up shortcuts for user applications, and one handles component branching in conjunction with end-of-life components. The other four perform actions at first boot that cannot currently be done statically during configuration building: RunOnce requests, DLL/COM registration, OC Manager requests, and generic commands.
There are some common properties between each of the FBA directives. DisplayName is the name of the directive as it appears in the component; it's also used during FBA processing to identify the directive being processed. ErrorControl specifies how FBA deals with errors when processing the directive. Setting this to zero (0) tells FBA to keep going if it sees an error. If ErrorControl is one (1), then FBA will halt when it hits an error. Reboot tells FBA whether a reboot is necessary after processing the directive—normally a reboot is not necessary. Start tells FBA when to process the directive; the settings are Boot (zero, 0), Installation (one, 1), End-user (two, 2), and Logon (three, 3). If this is not set, a setting of one (1), or Installation, is assumed. Timeout is how long FBA will wait for the directive to execute before it kills the thread. This setting is in seconds. Setting Timeout to zero (0) means we'll wait forever. Type specifies what kind of FBA directive is being executed. The settings for Type are Reserved (zero, 0), FBA Generic Command (one, 1), FBA DLL/COM registration (two, 2), and FBA OC Manager Request (three, 3). No value assumes a setting of one (1). Normally, this is set when you pick the FBA resource to add.
FBA Generic Commands
The FBA Generic Command executes a generic command during FBA processing. Settings include the FilePath, which points to the application or script to be processed (yes, I said script). Optional Arguments can be given as well. Flags can be specified as well, set to zero (0) to wait for the process to finish, or one (1) to continue after creating the process. You can use the FBA Generic Command to call a DLL entry point using RUNDLL32. The RUNDLL32 command line for a generic DLL entry point looks something like this:
RUNDLL32 <dllname>, <entrypoint>, <optional arguments>
Let's see how we do this in an FBA Generic Command. First, set the FilePath:
Then set the Arguments property:
Setupx.dll, InstallHinfSection 132 C:\Windows\Inf\Shell.inf
Fairly simple, right? You can make this work for any generic DLL. For a script, you would specify the script processor as the FilePath, and the name of the script and any other arguments in the Arguments property.
FBA DLL/COM Registration
Next, there's the FBA DLL/COM Registration. This is a very important process if you expect to be able to use your COM objects in your runtimes. Again, specify the FilePath property to the DLL you want to register. Set DLLRegister to True to register the DLL, or False to unregister it. If you need to call the DLLInstall entry point in the specified DLL, set DLLInstall to True. Arguments can be specified for DLLInstall as well. Flags is the important setting—it controls how and when DLLRegister and DLLInstall are called.
Flags=0: Call DLLRegisterServer, then DLLInstall Flags=1: Call DLLInstall, then DLLRegisterServer Flags=2: Call DLLUnregisterServer, then DLLInstall Flags=3: Call DLLInstall, then DLLUnregisterServer
FBA OC Manager Request
Next on our hit parade is the FBA OC Manager Request. OC Manager is the Optional Component Manager, which allows the integration of external components into the setup process. This FBA directive allows you to specify setup routines your component would normally run during a Windows XP setup. The OCName property specifies the name of the optional subcomponent, which belongs to a parent component group. Each optional subcomponent has an install section in an INF file associated with it—specify the INF file in the INFName property. FilePath specifies the name of the OC Manager helper DLL responsible for installing the optional component. DLLEntryPoint is the name of the function in the OC Manager helper DLL. The last property is GroupName, which is the name of the parent component group. This is required because optional components can belong to more than one parent group.
Since FBA runs before the device is shipped, anything placed directly in the Run or RunOnce keys will run during the FBA processing, which isn't usually what is expected. The RunOnce request FBA directive lets you set a Run, RunOnce, or RunOnceEx command that will run after FBA finishes. The ValueName property is the name of the command to run—this is the name of REG-SZ value that gets set. FilePath specifies the fully qualified pathname of the application to run. Arguments specifies any arguments to the FilePath—see the FBA Generic command for an example. Last is the Flags property, which is set as follows:
Flags=0: Set as a Run entry (default is no value set) Flags=1: Set as a RunOnce entry Flags=2: Set as a RunOnceEx enter
Service Data/PnP ID's/Component Branch
Service Data adds Windows XP service information to the runtime. Most of the properties are self-explanatory, if you know how to install a service. (In other words, I won't go over them all here.) PnP ID adds a PnP ID for your drivers to the registry. Again, if you know how to install a device driver, you shouldn't have any problems with these properties. Component Branch deals with end-of-life components, and specifies which specific component is to replace the end-of-life component (specified in the TargetVIGUID property).
That leaves us with Shortcuts, which are used to create shortcuts to applications. This is necessary, because you can't create shortcuts to non-existent applications in Windows XP. DstName is the name of the LNK file to create—MyShortcut.LNK for example. DstPath is where to put the LNK file. You can place it on the desktop by specifying the path parameter %16409%. TargetPath is the path to the application to be invoked by the shortcut. You should use parameterized paths here (such as the %16409% shown above). WorkDir specifies the working directory, and IconLocation specifies where the icon for the shortcut is located. If the icon is located in an executable on the system, follow the name with a comma and a zero-based number to indicate which icon resource to use. For example, to use the first icon in the IEXPLORE.EXE file, specify IEXPLORE.EXE,0. WindowStyle defines how the window for the application will be shown. Use the following values:
WindowStyle=1: Normal activation (default if no value is given). WindowStyle=3: Maximized window WindowStyle=7: Minimized window
Use Arguments to specify any arguments to the TargetPath, and Overwrite to specify whether we should overwrite any other shortcuts that may already be present. HotKey is used to specify a hotkey for the shortcut. The syntax for this property is [KeyModifier]KeyName, where KeyModifier is ALT, CTL, or SHIFT, and KeyName is a case-insensitive character from a-z, 0-9, or F1-F12.
How Does It Work?
Knowing how FBA works is important to knowing how to make it work for you. FBA isn't a single executable, but a collection of executables that are called by a controlling DLL. This controlling DLL calls a separate FBA executable to handle each type of FBA directive.
How does the master DLL know what to call? Each FBA directive is stored in the registry under the HKLM\SYSTEM\CurrentControlSet\Control\WindowsEmbedded\FBA registry key. Each FBA directive is a separate subkey under the master FBA key, with each subkey specifying a separate command. Each command has with it a set of properties that tells the master FBA DLL how to process the command. The appropriate FBA processing DLL is then called to process the command.
How about when to call everything? That's where the Phase property comes in. FBA Generic Command, FBA DLL/COM Registration, and FBA OC Manager Requests all have a Phase property associated with them. As FBA runs, its phase changes from 0 to 65,535 (phase 0 is reserved for use by the system). As FBA moves from phase to phase, the directives in each phase are executed. There is also an ordinal value assigned to each directive based on the build order specified in the component definition. Each directive in a given phase is executed according to the ordinal assigned to it. You can set the phase, but not the ordinal. Default phases for directives are as follows:
FBA DLL/COM Registration: Phase 4500 FBA Generic Command: Phase 0
Phases up to 8500 are reserved for system use—you should specify phases for your FBA directives after 8500. In addition, if you want a command to occur after system cloning (enabled by adding the System Cloning component), then specify the phase 12000. As a matter of fact, part of system cloning includes running FBRESEAL.EXE. You can set that phase to 12000, which means the device will be left in an unsealed state after FBA. This gives you a chance to manually make changes to the device runtime, and then to manually run FBRESEAL.EXE to seal the device in preparation for duplication. Normally, resealing takes place automatically at the end of FBA, leaving you with no way to test or tweak the runtime before cloning it.
What about reboots? Simple. FBA saves the phase and ordinal it's executing as it runs. When a reboot happens, FBA inspects the saved phase and ordinal and picks up where it left off.
Errors are handled by default in FBA. Dialog boxes are shown during FBA, and an FBALOG.TXT file is maintained in the \Windows\FBA folder on the device as FBA runs. If you run into problems with FBA running on your device, the first thing you should do is to inspect the FBALOG.TXT file. Most FBA errors are caused by low memory situations—devices with limited memory and no page file. In that case, you should increase the amount of memory on the device, or if possible, add a page file. If you add memory, remember it's only needed for FBA—you can remove it later.
We discussed a lot of FBA here, but there's always more. As usual, if you have specific questions, post them in the newsgroup for us. Next month, we start on our discussion of Target Designer. (I think we've exhausted the topic of component creation.)
And for those of you waiting with bated breath for the discussion of scripting components—sorry, but it's not available. Design issues surrounding the next version of Windows Embedded have rendered my article unfit for publication. I'll have to leave it unpublished for the time being. If you have specific scripting questions, post them to the newsgroup, and I'll do my best to answer them there.