Accessing .X Files
Regardless of the version of DirectX you are using (either DirectX 8 or 9),
the methods you use to access .X files are the same. In fact, the interfaces
have not changed names between the two newest versions of DirectX (8 and 9),
making it possible for you to quickly port your version 8 code to the newer
version 9 (and vice versa if you want).
The first step to accessing any .X file is to create an IDirectXFile
interface.
Applications use the methods of the IDirectXFile
interface to create instances of the IDirectXFileEnumObject and
IDirectXFileSaveObject interfaces, and to register templates. Deprecated.
IDirectXFile Members
Method |
Description |
IDirectXFile::CreateEnumObject |
Creates an enumerator object. Deprecated. |
IDirectXFile::CreateSaveObject |
Creates a save object. Deprecated. |
IDirectXFile::RegisterTemplates |
Registers custom templates. Deprecated. |
Remarks
The globally unique identifier (GUID) for the
IDirectXFile interface is IID_IDirectXFile.
The IDirectXFile interface is obtained by calling the
DirectXFileCreate function.
The LPDIRECTXFILE type is defined as a pointer to this
interface.
typedef interface IDirectXFile *LPDIRECTXFILE;
You need to call the DirectXFileCreate function, as shown in the following
bit of code:
IDirectXFile *pDXFile = NULL;
HRESULT Result = DirectXFileCreate(&pDXFile);
As you can see from the previous lines of code, the DirectXFileCreate
function takes one parameter−the pointer to an IDirectXFile interface. You can
quickly determine whether the function has succeeded in creating a valid,
IDirectXFile interface by using the SUCCEEDED or FAILED macro on the return code
from the DirectXFileCreate call.
Once you've successfully created the IDirectXFile interface, you can
optionally register any templates you'll be using (such as the DirectX standard
templates) and create an enumeration interface that weeds through the top−level
data objects within your .X files.
Registering Custom and Standard Templates
To save storage space and improve your data security, the .X interfaces allow
you to remove all template definitions from .X files and embed them into your
executable. This means that instead of the .X files defining templates, your
program has to do it. Don't worry−it's not as difficult as it sounds. As you'll
see in a moment, Microsoft has taken the liberty of doing the hard work by
defining the standard templates inside a couple include files, making everything
as simple as possible.
To register the standard templates (or any template, for that matter) from
within your program, you'll need to call upon the
IDirectXFile::RegisterTemplates function.
HRESULT IDirectXFile::RegisterTemplates(
LPVOID pvData, // buffer containing template definitions
DWORD cbSize); // # of bytes of data
The pvData parameter is merely a data buffer that contains the template
definitions in the exact format you'd see in an .X file. For example, you can
define a template data buffer like this:
char *Templates = "
"xof 0303txt 0032 \
template CustomTemplate { \
<4c944580−9e9a−11cf−ab43−0120af71e433> \
DWORD Length; \
array DWORD Values[Length]; \
}";
Note Notice that the template definition in Templates uses the backslash
character to represent a new line, and that the first line of text is a standard
.X file header.
Going back to RegisterTemplates, the cbSize parameter represents the size of
the template data buffer, which you can determine in this case by using the
strlen of the Templates buffer. Put together, you can register the templates
defined in Templates using the following code:
pFile−>RegisterTemplates(Templates, strlen(Templates));
Now let's get back to the topic at hand−registering the standard templates.
You've seen RegisterTemplates at work. In order to register the standard
templates, you need to include two additional files in your project−rmxftmpl.h
and rmxfguid.h. These two files define the template
definitions and GUIDs of the standard templates, respectively.
Tip To remember rmxftmpl.h and
rmxfguid.h, just remember that rmxf stands for retained mode x−file, tmpl means
template, and guid means globally unique identifier.
Inside the rmxftmpl.h file, you'll find the D3DRM_XTEMPLATES template data
buffer and the D3DRM_XTEMPLATE_BYTES macro. These are used in the call to
RegisterTemplates to register the standard templates, as you can see here:
pFile−>RegisterTemplates(D3DRM_XTEMPLATES,
D3DRM_XTEMPLATE_BYTES);
That's right; just by calling the above bit of code, you have successfully
registered the standard templates, and you're ready to move on! A word of advice
before you do: Once you begin using the .X format for your own custom templates
and data, don't forget that using RegisterTemplates works perfectly for
registering your own custom template definitions!
Opening an .X File
After you've created an IDirectXFile interface and registered the templates
you'll be using, you need to open the .X file and begin enumerating the data
objects within it. The process of opening the .X file and creating an
enumeration object occurs in one call to the IDirectXFile::CreateEnumObject
function.
HRESULT IDirectXfile::CreateEnumObject(
LPVOID pvSource, // .X filename
DXFILELOADOPTIONS dwLoadOptions, // Load options
LPDIRECTXFILEENUMOBJECT* ppEnumObj); // Enum interface
When you call the CreateEnumObject function, specify the file name of the .X
file to load as pvSource and the interface you'll be using as ppEnumObj. As for
dwLoadOptions, you should specify the value DXFILELOAD_FROMFILE, which tells
DirectX to load the file from disk. Other possible values for dwLoadOptions are
DXFILELOAD_FROMRESOURCE, DXFILELOAD_FROMMEMORY, and DXFILELOAD_FROMURL. These
values tell DirectX to load the .X file from a resource, memory buffer, or
network URL, respectively. Yep, that's right−you can load .X files directly over
the Internet!
Tip To load an .X file from the Internet
using a URL, specify the complete network path in pvSource.To load from a
resource or memory location, just specify the resource handle or memory pointer
(both cast as LPVOID) in pvSource.
Continue the example and create an enumeration object for the .X file. The
following code will create an enumeration object used to parse a file from a
disk.
// Filename = filename to load ("test.x" for example)
IDirectXFileEnumObject *pEnum;
pFile−>CreateEnumObject((LPVOID)Filename, DXFILELOAD_FROMFILE, &pEnum);
From the code's comments, you can see that Filename points to a valid file
name−in this case, test.x. Once successfully called, the CreateEnumObject gives
you a valid enumeration object (only one is required per open .X file), ready to
do all your enumeration dirty work.