winex11: Use the create_pixmap_from_image helper to select DIB pattern brushes.
[wine] / dlls / d3dxof / d3dxof.c
1 /*
2  * Implementation of DirectX File Interfaces
3  *
4  * Copyright 2004, 2008, 2010 Christian Costa
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/debug.h"
23
24 #define COBJMACROS
25
26 #include "winbase.h"
27 #include "wingdi.h"
28
29 #include "d3dxof_private.h"
30 #include "dxfile.h"
31
32 #include <stdio.h>
33
34 WINE_DEFAULT_DEBUG_CHANNEL(d3dxof);
35 WINE_DECLARE_DEBUG_CHANNEL(d3dxof_dump);
36
37 static const struct IDirectXFileVtbl IDirectXFile_Vtbl;
38 static const struct IDirectXFileBinaryVtbl IDirectXFileBinary_Vtbl;
39 static const struct IDirectXFileDataVtbl IDirectXFileData_Vtbl;
40 static const struct IDirectXFileDataReferenceVtbl IDirectXFileDataReference_Vtbl;
41 static const struct IDirectXFileEnumObjectVtbl IDirectXFileEnumObject_Vtbl;
42 static const struct IDirectXFileObjectVtbl IDirectXFileObject_Vtbl;
43 static const struct IDirectXFileSaveObjectVtbl IDirectXFileSaveObject_Vtbl;
44
45 static HRESULT IDirectXFileDataReferenceImpl_Create(IDirectXFileDataReferenceImpl** ppObj);
46 static HRESULT IDirectXFileEnumObjectImpl_Create(IDirectXFileEnumObjectImpl** ppObj);
47 static HRESULT IDirectXFileSaveObjectImpl_Create(IDirectXFileSaveObjectImpl** ppObj);
48
49 HRESULT IDirectXFileImpl_Create(IUnknown* pUnkOuter, LPVOID* ppObj)
50 {
51     IDirectXFileImpl* object;
52
53     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
54       
55     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileImpl));
56     if (!object)
57     {
58         ERR("Out of memory\n");
59         return DXFILEERR_BADALLOC;
60     }
61
62     object->IDirectXFile_iface.lpVtbl = &IDirectXFile_Vtbl;
63     object->ref = 1;
64
65     *ppObj = &object->IDirectXFile_iface;
66
67     return S_OK;
68 }
69
70 static inline IDirectXFileImpl *impl_from_IDirectXFile(IDirectXFile *iface)
71 {
72     return CONTAINING_RECORD(iface, IDirectXFileImpl, IDirectXFile_iface);
73 }
74
75 /*** IUnknown methods ***/
76 static HRESULT WINAPI IDirectXFileImpl_QueryInterface(IDirectXFile* iface, REFIID riid, void** ppvObject)
77 {
78   IDirectXFileImpl *This = impl_from_IDirectXFile(iface);
79
80   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
81
82   if (IsEqualGUID(riid, &IID_IUnknown)
83       || IsEqualGUID(riid, &IID_IDirectXFile))
84   {
85     IUnknown_AddRef(iface);
86     *ppvObject = &This->IDirectXFile_iface;
87     return S_OK;
88   }
89
90   ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
91   return E_NOINTERFACE;
92 }
93
94 static ULONG WINAPI IDirectXFileImpl_AddRef(IDirectXFile* iface)
95 {
96   IDirectXFileImpl *This = impl_from_IDirectXFile(iface);
97   ULONG ref = InterlockedIncrement(&This->ref);
98
99   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
100
101   return ref;
102 }
103
104 static ULONG WINAPI IDirectXFileImpl_Release(IDirectXFile* iface)
105 {
106   IDirectXFileImpl *This = impl_from_IDirectXFile(iface);
107   ULONG ref = InterlockedDecrement(&This->ref);
108
109   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
110
111   if (!ref)
112     HeapFree(GetProcessHeap(), 0, This);
113
114   return ref;
115 }
116
117 /*** IDirectXFile methods ***/
118 static HRESULT WINAPI IDirectXFileImpl_CreateEnumObject(IDirectXFile* iface, LPVOID pvSource, DXFILELOADOPTIONS dwLoadOptions, LPDIRECTXFILEENUMOBJECT* ppEnumObj)
119 {
120   IDirectXFileImpl *This = impl_from_IDirectXFile(iface);
121   IDirectXFileEnumObjectImpl* object;
122   HRESULT hr;
123   LPBYTE file_buffer;
124   DWORD file_size;
125
126   TRACE("(%p/%p)->(%p,%x,%p)\n", This, iface, pvSource, dwLoadOptions, ppEnumObj);
127
128   if (!ppEnumObj)
129     return DXFILEERR_BADVALUE;
130
131   /* Only lowest 4 bits are relevant in DXFILELOADOPTIONS */
132   dwLoadOptions &= 0xF;
133
134   hr = IDirectXFileEnumObjectImpl_Create(&object);
135   if (FAILED(hr))
136     return hr;
137
138   if (dwLoadOptions == DXFILELOAD_FROMFILE)
139   {
140     HANDLE hFile, file_mapping;
141
142     TRACE("Open source file '%s'\n", (char*)pvSource);
143
144     hFile = CreateFileA(pvSource, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
145     if (hFile == INVALID_HANDLE_VALUE)
146     {
147       TRACE("File '%s' not found\n", (char*)pvSource);
148       return DXFILEERR_FILENOTFOUND;
149     }
150
151     file_size = GetFileSize(hFile, NULL);
152
153     file_mapping = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
154     CloseHandle(hFile);
155     if (!file_mapping)
156     {
157       hr = DXFILEERR_BADFILETYPE;
158       goto error;
159     }
160
161     object->mapped_memory = MapViewOfFile(file_mapping, FILE_MAP_READ, 0, 0, 0);
162     CloseHandle(file_mapping);
163     if (!object->mapped_memory)
164     {
165       hr = DXFILEERR_BADFILETYPE;
166       goto error;
167     }
168     file_buffer = object->mapped_memory;
169   }
170   else if (dwLoadOptions == DXFILELOAD_FROMRESOURCE)
171   {
172     HRSRC resource_info;
173     HGLOBAL resource_data;
174     LPDXFILELOADRESOURCE lpdxflr = pvSource;
175
176     TRACE("Source in resource (module = %p, name = %s, type = %s\n", lpdxflr->hModule, debugstr_a(lpdxflr->lpName), debugstr_a(lpdxflr->lpType));
177
178     resource_info = FindResourceA(lpdxflr->hModule, lpdxflr->lpName, lpdxflr->lpType);
179     if (!resource_info)
180     {
181       hr = DXFILEERR_RESOURCENOTFOUND;
182       goto error;
183     }
184
185     file_size = SizeofResource(lpdxflr->hModule, resource_info);
186
187     resource_data = LoadResource(lpdxflr->hModule, resource_info);
188     if (!resource_data)
189     {
190       hr = DXFILEERR_BADRESOURCE;
191       goto error;
192     }
193
194     file_buffer = LockResource(resource_data);
195     if (!file_buffer)
196     {
197       hr = DXFILEERR_BADRESOURCE;
198       goto error;
199     }
200   }
201   else if (dwLoadOptions == DXFILELOAD_FROMMEMORY)
202   {
203     LPDXFILELOADMEMORY lpdxflm = pvSource;
204
205     TRACE("Source in memory at %p with size %d\n", lpdxflm->lpMemory, lpdxflm->dSize);
206
207     file_buffer = lpdxflm->lpMemory;
208     file_size = lpdxflm->dSize;
209   }
210   else
211   {
212     FIXME("Source type %d is not handled yet\n", dwLoadOptions);
213     hr = DXFILEERR_NOTDONEYET;
214     goto error;
215   }
216
217   TRACE("File size is %d bytes\n", file_size);
218
219   if (TRACE_ON(d3dxof_dump))
220   {
221     static USHORT num;
222     char tmp[12];
223     HANDLE file;
224     sprintf(tmp, "file%05u.x", num++);
225
226     file = CreateFileA(tmp, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
227     if (file != INVALID_HANDLE_VALUE)
228     {
229       WriteFile(file, file_buffer, file_size, NULL, NULL);
230       CloseHandle(file);
231     }
232   }
233
234   object->pDirectXFile = This;
235
236   object->buf.pdxf = This;
237   object->buf.token_present = FALSE;
238   object->buf.buffer = file_buffer;
239   object->buf.rem_bytes = file_size;
240   hr = parse_header(&object->buf, &object->decomp_buffer);
241   if (FAILED(hr))
242     goto error;
243
244   if (!parse_templates(&object->buf)) {
245     hr = DXFILEERR_BADVALUE;
246     goto error;
247   }
248
249   if (TRACE_ON(d3dxof))
250   {
251     int i;
252     TRACE("Registered templates (%d):\n", This->nb_xtemplates);
253     for (i = 0; i < This->nb_xtemplates; i++)
254       DPRINTF("%s - %s\n", This->xtemplates[i].name, debugstr_guid(&This->xtemplates[i].class_id));
255   }
256
257   *ppEnumObj = &object->IDirectXFileEnumObject_iface;
258
259   return DXFILE_OK;
260
261 error:
262   IDirectXFileEnumObject_Release(&object->IDirectXFileEnumObject_iface);
263   *ppEnumObj = NULL;
264
265   return hr;
266 }
267
268 static HRESULT WINAPI IDirectXFileImpl_CreateSaveObject(IDirectXFile* iface, LPCSTR szFileName, DXFILEFORMAT dwFileFormat, LPDIRECTXFILESAVEOBJECT* ppSaveObj)
269 {
270   IDirectXFileImpl *This = impl_from_IDirectXFile(iface);
271   IDirectXFileSaveObjectImpl *object;
272   HRESULT hr;
273
274   FIXME("(%p/%p)->(%s,%x,%p) partial stub!\n", This, iface, szFileName, dwFileFormat, ppSaveObj);
275
276   if (!szFileName || !ppSaveObj)
277     return E_POINTER;
278
279   hr = IDirectXFileSaveObjectImpl_Create(&object);
280   if (SUCCEEDED(hr))
281     *ppSaveObj = &object->IDirectXFileSaveObject_iface;
282   return hr;
283 }
284
285 static HRESULT WINAPI IDirectXFileImpl_RegisterTemplates(IDirectXFile* iface, LPVOID pvData, DWORD cbSize)
286 {
287   IDirectXFileImpl *This = impl_from_IDirectXFile(iface);
288   parse_buffer buf;
289   HRESULT hr;
290   LPBYTE decomp_buffer = NULL;
291
292   buf.buffer = pvData;
293   buf.rem_bytes = cbSize;
294   buf.txt = FALSE;
295   buf.token_present = FALSE;
296   buf.pdxf = This;
297
298   TRACE("(%p/%p)->(%p,%d)\n", This, iface, pvData, cbSize);
299
300   if (!pvData)
301     return DXFILEERR_BADVALUE;
302
303   if (TRACE_ON(d3dxof_dump))
304   {
305     static USHORT num;
306     char tmp[16];
307     HANDLE file;
308     sprintf(tmp, "template%05u.x", num++);
309
310     file = CreateFileA(tmp, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
311     if (file != INVALID_HANDLE_VALUE)
312     {
313       WriteFile(file, pvData, cbSize, NULL, NULL);
314       CloseHandle(file);
315     }
316   }
317
318   hr = parse_header(&buf, &decomp_buffer);
319   if (FAILED(hr))
320     goto cleanup;
321
322   if (!parse_templates(&buf)) {
323     hr = DXFILEERR_BADVALUE;
324     goto cleanup;
325   }
326
327   if (TRACE_ON(d3dxof))
328   {
329     int i;
330     TRACE("Registered templates (%d):\n", This->nb_xtemplates);
331     for (i = 0; i < This->nb_xtemplates; i++)
332       DPRINTF("%s - %s\n", This->xtemplates[i].name, debugstr_guid(&This->xtemplates[i].class_id));
333   }
334
335   hr = DXFILE_OK;
336 cleanup:
337   HeapFree(GetProcessHeap(), 0, decomp_buffer);
338   return hr;
339 }
340
341 static const IDirectXFileVtbl IDirectXFile_Vtbl =
342 {
343   IDirectXFileImpl_QueryInterface,
344   IDirectXFileImpl_AddRef,
345   IDirectXFileImpl_Release,
346   IDirectXFileImpl_CreateEnumObject,
347   IDirectXFileImpl_CreateSaveObject,
348   IDirectXFileImpl_RegisterTemplates
349 };
350
351 static HRESULT IDirectXFileBinaryImpl_Create(IDirectXFileBinaryImpl** ppObj)
352 {
353     IDirectXFileBinaryImpl* object;
354
355     TRACE("(%p)\n", ppObj);
356
357     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileBinaryImpl));
358     if (!object)
359     {
360         ERR("Out of memory\n");
361         return DXFILEERR_BADALLOC;
362     }
363
364     object->IDirectXFileBinary_iface.lpVtbl = &IDirectXFileBinary_Vtbl;
365     object->ref = 1;
366
367     *ppObj = object;
368
369     return DXFILE_OK;
370 }
371
372 static inline IDirectXFileBinaryImpl *impl_from_IDirectXFileBinary(IDirectXFileBinary *iface)
373 {
374     return CONTAINING_RECORD(iface, IDirectXFileBinaryImpl, IDirectXFileBinary_iface);
375 }
376
377 /*** IUnknown methods ***/
378 static HRESULT WINAPI IDirectXFileBinaryImpl_QueryInterface(IDirectXFileBinary* iface, REFIID riid, void** ppvObject)
379 {
380   IDirectXFileBinaryImpl *This = impl_from_IDirectXFileBinary(iface);
381
382   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
383
384   if (IsEqualGUID(riid, &IID_IUnknown)
385       || IsEqualGUID(riid, &IID_IDirectXFileObject)
386       || IsEqualGUID(riid, &IID_IDirectXFileBinary))
387   {
388     IUnknown_AddRef(iface);
389     *ppvObject = &This->IDirectXFileBinary_iface;
390     return S_OK;
391   }
392
393   /* Do not print an error for interfaces that can be queried to retrieve the type of the object */
394   if (!IsEqualGUID(riid, &IID_IDirectXFileData)
395       && !IsEqualGUID(riid, &IID_IDirectXFileDataReference))
396     ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
397
398   return E_NOINTERFACE;
399 }
400
401 static ULONG WINAPI IDirectXFileBinaryImpl_AddRef(IDirectXFileBinary* iface)
402 {
403   IDirectXFileBinaryImpl *This = impl_from_IDirectXFileBinary(iface);
404   ULONG ref = InterlockedIncrement(&This->ref);
405
406   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
407
408   return ref;
409 }
410
411 static ULONG WINAPI IDirectXFileBinaryImpl_Release(IDirectXFileBinary* iface)
412 {
413   IDirectXFileBinaryImpl *This = impl_from_IDirectXFileBinary(iface);
414   ULONG ref = InterlockedDecrement(&This->ref);
415
416   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
417
418   if (!ref)
419     HeapFree(GetProcessHeap(), 0, This);
420
421   return ref;
422 }
423
424 /*** IDirectXFileObject methods ***/
425 static HRESULT WINAPI IDirectXFileBinaryImpl_GetName(IDirectXFileBinary* iface, LPSTR pstrNameBuf, LPDWORD pdwBufLen)
426
427 {
428   IDirectXFileBinaryImpl *This = impl_from_IDirectXFileBinary(iface);
429
430   FIXME("(%p/%p)->(%p,%p) stub!\n", This, iface, pstrNameBuf, pdwBufLen); 
431
432   return DXFILEERR_BADVALUE;
433 }
434
435 static HRESULT WINAPI IDirectXFileBinaryImpl_GetId(IDirectXFileBinary* iface, LPGUID pGuid)
436 {
437   IDirectXFileBinaryImpl *This = impl_from_IDirectXFileBinary(iface);
438
439   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pGuid); 
440
441   return DXFILEERR_BADVALUE;
442 }
443
444 /*** IDirectXFileBinary methods ***/
445 static HRESULT WINAPI IDirectXFileBinaryImpl_GetSize(IDirectXFileBinary* iface, DWORD* pcbSize)
446 {
447   IDirectXFileBinaryImpl *This = impl_from_IDirectXFileBinary(iface);
448
449   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pcbSize); 
450
451   return DXFILEERR_BADVALUE;
452 }
453
454 static HRESULT WINAPI IDirectXFileBinaryImpl_GetMimeType(IDirectXFileBinary* iface, LPCSTR* pszMimeType)
455 {
456   IDirectXFileBinaryImpl *This = impl_from_IDirectXFileBinary(iface);
457
458   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pszMimeType);
459
460   return DXFILEERR_BADVALUE;
461 }
462
463 static HRESULT WINAPI IDirectXFileBinaryImpl_Read(IDirectXFileBinary* iface, LPVOID pvData, DWORD cbSize, LPDWORD pcbRead)
464 {
465   IDirectXFileBinaryImpl *This = impl_from_IDirectXFileBinary(iface);
466
467   FIXME("(%p/%p)->(%p, %d, %p) stub!\n", This, iface, pvData, cbSize, pcbRead);
468
469   return DXFILEERR_BADVALUE;
470 }
471
472 static const IDirectXFileBinaryVtbl IDirectXFileBinary_Vtbl =
473 {
474     IDirectXFileBinaryImpl_QueryInterface,
475     IDirectXFileBinaryImpl_AddRef,
476     IDirectXFileBinaryImpl_Release,
477     IDirectXFileBinaryImpl_GetName,
478     IDirectXFileBinaryImpl_GetId,
479     IDirectXFileBinaryImpl_GetSize,
480     IDirectXFileBinaryImpl_GetMimeType,
481     IDirectXFileBinaryImpl_Read
482 };
483
484 static HRESULT IDirectXFileDataImpl_Create(IDirectXFileDataImpl** ppObj)
485 {
486     IDirectXFileDataImpl* object;
487
488     TRACE("(%p)\n", ppObj);
489       
490     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileDataImpl));
491     if (!object)
492     {
493         ERR("Out of memory\n");
494         return DXFILEERR_BADALLOC;
495     }
496
497     object->IDirectXFileData_iface.lpVtbl = &IDirectXFileData_Vtbl;
498     object->ref = 1;
499
500     *ppObj = object;
501     
502     return S_OK;
503 }
504
505 static inline IDirectXFileDataImpl *impl_from_IDirectXFileData(IDirectXFileData *iface)
506 {
507     return CONTAINING_RECORD(iface, IDirectXFileDataImpl, IDirectXFileData_iface);
508 }
509
510 /*** IUnknown methods ***/
511 static HRESULT WINAPI IDirectXFileDataImpl_QueryInterface(IDirectXFileData* iface, REFIID riid, void** ppvObject)
512 {
513   IDirectXFileDataImpl *This = impl_from_IDirectXFileData(iface);
514
515   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
516
517   if (IsEqualGUID(riid, &IID_IUnknown)
518       || IsEqualGUID(riid, &IID_IDirectXFileObject)
519       || IsEqualGUID(riid, &IID_IDirectXFileData))
520   {
521     IUnknown_AddRef(iface);
522     *ppvObject = &This->IDirectXFileData_iface;
523     return S_OK;
524   }
525
526   /* Do not print an error for interfaces that can be queried to retrieve the type of the object */
527   if (!IsEqualGUID(riid, &IID_IDirectXFileBinary)
528       && !IsEqualGUID(riid, &IID_IDirectXFileDataReference))
529     ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
530
531   return E_NOINTERFACE;
532 }
533
534 static ULONG WINAPI IDirectXFileDataImpl_AddRef(IDirectXFileData* iface)
535 {
536   IDirectXFileDataImpl *This = impl_from_IDirectXFileData(iface);
537   ULONG ref = InterlockedIncrement(&This->ref);
538
539   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
540
541   return ref;
542 }
543
544 static ULONG WINAPI IDirectXFileDataImpl_Release(IDirectXFileData* iface)
545 {
546   IDirectXFileDataImpl *This = impl_from_IDirectXFileData(iface);
547   ULONG ref = InterlockedDecrement(&This->ref);
548
549   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
550
551   if (!ref)
552   {
553     if (!This->level && !This->from_ref)
554     {
555       HeapFree(GetProcessHeap(), 0, This->pstrings);
556       if (This->pobj)
557       {
558         HeapFree(GetProcessHeap(), 0, This->pobj->pdata);
559         HeapFree(GetProcessHeap(), 0, This->pobj);
560       }
561     }
562     HeapFree(GetProcessHeap(), 0, This);
563   }
564
565   return ref;
566 }
567
568 /*** IDirectXFileObject methods ***/
569 static HRESULT WINAPI IDirectXFileDataImpl_GetName(IDirectXFileData* iface, LPSTR pstrNameBuf, LPDWORD pdwBufLen)
570 {
571   IDirectXFileDataImpl *This = impl_from_IDirectXFileData(iface);
572   DWORD len;
573
574   TRACE("(%p/%p)->(%p,%p)\n", This, iface, pstrNameBuf, pdwBufLen);
575
576   if (!pdwBufLen)
577     return DXFILEERR_BADVALUE;
578
579   len = strlen(This->pobj->name);
580   if (len)
581     len++;
582
583   if (pstrNameBuf) {
584     if (*pdwBufLen < len)
585       return DXFILEERR_BADVALUE;
586     CopyMemory(pstrNameBuf, This->pobj->name, len);
587   }
588   *pdwBufLen = len;
589
590   return DXFILE_OK;
591 }
592
593 static HRESULT WINAPI IDirectXFileDataImpl_GetId(IDirectXFileData* iface, LPGUID pGuid)
594 {
595   IDirectXFileDataImpl *This = impl_from_IDirectXFileData(iface);
596
597   TRACE("(%p/%p)->(%p)\n", This, iface, pGuid);
598
599   if (!pGuid)
600     return DXFILEERR_BADVALUE;
601
602   memcpy(pGuid, &This->pobj->class_id, 16);
603
604   return DXFILE_OK;
605 }
606
607 /*** IDirectXFileData methods ***/
608 static HRESULT WINAPI IDirectXFileDataImpl_GetData(IDirectXFileData* iface, LPCSTR szMember, DWORD* pcbSize, void** ppvData)
609 {
610   IDirectXFileDataImpl *This = impl_from_IDirectXFileData(iface);
611
612   TRACE("(%p/%p)->(%s,%p,%p)\n", This, iface, debugstr_a(szMember), pcbSize, ppvData);
613
614   if (!pcbSize || !ppvData)
615     return DXFILEERR_BADVALUE;
616
617   if (szMember)
618   {
619     int i;
620     for (i = 0; i < This->pobj->nb_members; i++)
621       if (!strcmp(This->pobj->members[i].name, szMember))
622         break;
623     if (i == This->pobj->nb_members)
624     {
625       WARN("Unknown member '%s'\n", szMember);
626       return DXFILEERR_BADDATAREFERENCE;
627     }
628     *pcbSize = This->pobj->members[i].size;
629     *ppvData = This->pobj->root->pdata + This->pobj->members[i].start;
630   }
631   else
632   {
633     *pcbSize = This->pobj->size;
634     *ppvData = This->pobj->root->pdata + This->pobj->pos_data;
635   }
636
637   return DXFILE_OK;
638 }
639
640 static HRESULT WINAPI IDirectXFileDataImpl_GetType(IDirectXFileData* iface, const GUID** pguid)
641 {
642   IDirectXFileDataImpl *This = impl_from_IDirectXFileData(iface);
643   static GUID guid;
644
645   TRACE("(%p/%p)->(%p)\n", This, iface, pguid);
646
647   if (!pguid)
648     return DXFILEERR_BADVALUE;
649
650   memcpy(&guid, &This->pobj->type, 16);
651   *pguid = &guid;
652
653   return DXFILE_OK;
654 }
655
656 static HRESULT WINAPI IDirectXFileDataImpl_GetNextObject(IDirectXFileData* iface, LPDIRECTXFILEOBJECT* ppChildObj)
657 {
658   HRESULT hr;
659   IDirectXFileDataImpl *This = impl_from_IDirectXFileData(iface);
660
661   TRACE("(%p/%p)->(%p)\n", This, iface, ppChildObj);
662
663   if (This->cur_enum_object >= This->pobj->nb_children)
664   {
665     *ppChildObj = NULL;
666     return DXFILEERR_NOMOREOBJECTS;
667   }
668
669   if (This->from_ref && (This->level >= 1))
670   {
671     /* Only 2 levels can be enumerated if the object is obtained from a reference */
672     *ppChildObj = NULL;
673     return DXFILEERR_NOMOREOBJECTS;
674   }
675
676   if (This->pobj->children[This->cur_enum_object]->binary)
677   {
678     IDirectXFileBinaryImpl *object;
679
680     hr = IDirectXFileBinaryImpl_Create(&object);
681     if (FAILED(hr))
682       return hr;
683
684     *ppChildObj = (LPDIRECTXFILEOBJECT)&object->IDirectXFileBinary_iface;
685   }
686   else if (This->pobj->children[This->cur_enum_object]->ptarget)
687   {
688     IDirectXFileDataReferenceImpl *object;
689
690     hr = IDirectXFileDataReferenceImpl_Create(&object);
691     if (FAILED(hr))
692       return hr;
693
694     object->ptarget = This->pobj->children[This->cur_enum_object++]->ptarget;
695
696     *ppChildObj = (LPDIRECTXFILEOBJECT)&object->IDirectXFileDataReference_iface;
697   }
698   else
699   {
700     IDirectXFileDataImpl *object;
701
702     hr = IDirectXFileDataImpl_Create(&object);
703     if (FAILED(hr))
704       return hr;
705
706     object->pobj = This->pobj->children[This->cur_enum_object++];
707     object->cur_enum_object = 0;
708     object->from_ref = This->from_ref;
709     object->level = This->level + 1;
710
711     *ppChildObj = (LPDIRECTXFILEOBJECT)&object->IDirectXFileData_iface;
712   }
713
714   return DXFILE_OK;
715 }
716
717 static HRESULT WINAPI IDirectXFileDataImpl_AddDataObject(IDirectXFileData* iface, LPDIRECTXFILEDATA pDataObj)
718 {
719   IDirectXFileDataImpl *This = impl_from_IDirectXFileData(iface);
720
721   FIXME("(%p/%p)->(%p) stub!\n", This, iface, pDataObj); 
722
723   return DXFILEERR_BADVALUE;
724 }
725
726 static HRESULT WINAPI IDirectXFileDataImpl_AddDataReference(IDirectXFileData* iface, LPCSTR szRef, const GUID* pguidRef)
727 {
728   IDirectXFileDataImpl *This = impl_from_IDirectXFileData(iface);
729
730   FIXME("(%p/%p)->(%s,%p) stub!\n", This, iface, szRef, pguidRef); 
731
732   return DXFILEERR_BADVALUE;
733 }
734
735 static HRESULT WINAPI IDirectXFileDataImpl_AddBinaryObject(IDirectXFileData* iface, LPCSTR szName, const GUID* pguid, LPCSTR szMimeType, LPVOID pvData, DWORD cbSize)
736 {
737   IDirectXFileDataImpl *This = impl_from_IDirectXFileData(iface);
738
739   FIXME("(%p/%p)->(%s,%p,%s,%p,%d) stub!\n", This, iface, szName, pguid, szMimeType, pvData, cbSize);
740
741   return DXFILEERR_BADVALUE;
742 }
743
744 static const IDirectXFileDataVtbl IDirectXFileData_Vtbl =
745 {
746     IDirectXFileDataImpl_QueryInterface,
747     IDirectXFileDataImpl_AddRef,
748     IDirectXFileDataImpl_Release,
749     IDirectXFileDataImpl_GetName,
750     IDirectXFileDataImpl_GetId,
751     IDirectXFileDataImpl_GetData,
752     IDirectXFileDataImpl_GetType,
753     IDirectXFileDataImpl_GetNextObject,
754     IDirectXFileDataImpl_AddDataObject,
755     IDirectXFileDataImpl_AddDataReference,
756     IDirectXFileDataImpl_AddBinaryObject
757 };
758
759 static HRESULT IDirectXFileDataReferenceImpl_Create(IDirectXFileDataReferenceImpl** ppObj)
760 {
761     IDirectXFileDataReferenceImpl* object;
762
763     TRACE("(%p)\n", ppObj);
764       
765     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileDataReferenceImpl));
766     if (!object)
767     {
768         ERR("Out of memory\n");
769         return DXFILEERR_BADALLOC;
770     }
771
772     object->IDirectXFileDataReference_iface.lpVtbl = &IDirectXFileDataReference_Vtbl;
773     object->ref = 1;
774
775     *ppObj = object;
776     
777     return S_OK;
778 }
779
780 static inline IDirectXFileDataReferenceImpl *impl_from_IDirectXFileDataReference(IDirectXFileDataReference *iface)
781 {
782     return CONTAINING_RECORD(iface, IDirectXFileDataReferenceImpl, IDirectXFileDataReference_iface);
783 }
784
785 /*** IUnknown methods ***/
786 static HRESULT WINAPI IDirectXFileDataReferenceImpl_QueryInterface(IDirectXFileDataReference* iface, REFIID riid, void** ppvObject)
787 {
788   IDirectXFileDataReferenceImpl *This = impl_from_IDirectXFileDataReference(iface);
789
790   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
791
792   if (IsEqualGUID(riid, &IID_IUnknown)
793       || IsEqualGUID(riid, &IID_IDirectXFileObject)
794       || IsEqualGUID(riid, &IID_IDirectXFileDataReference))
795   {
796     IUnknown_AddRef(iface);
797     *ppvObject = &This->IDirectXFileDataReference_iface;
798     return S_OK;
799   }
800
801   /* Do not print an error for interfaces that can be queried to retrieve the type of the object */
802   if (!IsEqualGUID(riid, &IID_IDirectXFileData)
803       && !IsEqualGUID(riid, &IID_IDirectXFileBinary))
804     ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
805
806   return E_NOINTERFACE;
807 }
808
809 static ULONG WINAPI IDirectXFileDataReferenceImpl_AddRef(IDirectXFileDataReference* iface)
810 {
811   IDirectXFileDataReferenceImpl *This = impl_from_IDirectXFileDataReference(iface);
812   ULONG ref = InterlockedIncrement(&This->ref);
813
814   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
815
816   return ref;
817 }
818
819 static ULONG WINAPI IDirectXFileDataReferenceImpl_Release(IDirectXFileDataReference* iface)
820 {
821   IDirectXFileDataReferenceImpl *This = impl_from_IDirectXFileDataReference(iface);
822   ULONG ref = InterlockedDecrement(&This->ref);
823
824   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
825
826   if (!ref)
827     HeapFree(GetProcessHeap(), 0, This);
828
829   return ref;
830 }
831
832 /*** IDirectXFileObject methods ***/
833 static HRESULT WINAPI IDirectXFileDataReferenceImpl_GetName(IDirectXFileDataReference* iface, LPSTR pstrNameBuf, LPDWORD pdwBufLen)
834 {
835   IDirectXFileDataReferenceImpl *This = impl_from_IDirectXFileDataReference(iface);
836   DWORD len;
837
838   TRACE("(%p/%p)->(%p,%p)\n", This, iface, pstrNameBuf, pdwBufLen);
839
840   if (!pdwBufLen)
841     return DXFILEERR_BADVALUE;
842
843   len = strlen(This->ptarget->name);
844   if (len)
845     len++;
846
847   if (pstrNameBuf) {
848     if (*pdwBufLen < len)
849       return DXFILEERR_BADVALUE;
850     CopyMemory(pstrNameBuf, This->ptarget->name, len);
851   }
852   *pdwBufLen = len;
853
854   return DXFILE_OK;
855 }
856
857 static HRESULT WINAPI IDirectXFileDataReferenceImpl_GetId(IDirectXFileDataReference* iface, LPGUID pGuid)
858 {
859   IDirectXFileDataReferenceImpl *This = impl_from_IDirectXFileDataReference(iface);
860
861   TRACE("(%p/%p)->(%p)\n", This, iface, pGuid);
862
863   if (!pGuid)
864     return DXFILEERR_BADVALUE;
865
866   memcpy(pGuid, &This->ptarget->class_id, 16);
867
868   return DXFILE_OK;
869 }
870
871 /*** IDirectXFileDataReference ***/
872 static HRESULT WINAPI IDirectXFileDataReferenceImpl_Resolve(IDirectXFileDataReference* iface, LPDIRECTXFILEDATA* ppDataObj)
873 {
874   IDirectXFileDataReferenceImpl *This = impl_from_IDirectXFileDataReference(iface);
875   IDirectXFileDataImpl *object;
876   HRESULT hr;
877
878   TRACE("(%p/%p)->(%p)\n", This, iface, ppDataObj);
879
880   if (!ppDataObj)
881     return DXFILEERR_BADVALUE;
882
883   hr = IDirectXFileDataImpl_Create(&object);
884   if (FAILED(hr))
885     return hr;
886
887   object->pobj = This->ptarget;
888   object->cur_enum_object = 0;
889   object->level = 0;
890   object->from_ref = TRUE;
891
892   *ppDataObj = (LPDIRECTXFILEDATA)object;
893
894   return DXFILE_OK;
895 }
896
897 static const IDirectXFileDataReferenceVtbl IDirectXFileDataReference_Vtbl =
898 {
899     IDirectXFileDataReferenceImpl_QueryInterface,
900     IDirectXFileDataReferenceImpl_AddRef,
901     IDirectXFileDataReferenceImpl_Release,
902     IDirectXFileDataReferenceImpl_GetName,
903     IDirectXFileDataReferenceImpl_GetId,
904     IDirectXFileDataReferenceImpl_Resolve
905 };
906
907 static HRESULT IDirectXFileEnumObjectImpl_Create(IDirectXFileEnumObjectImpl** ppObj)
908 {
909     IDirectXFileEnumObjectImpl* object;
910
911     TRACE("(%p)\n", ppObj);
912       
913     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileEnumObjectImpl));
914     if (!object)
915     {
916         ERR("Out of memory\n");
917         return DXFILEERR_BADALLOC;
918     }
919
920     object->IDirectXFileEnumObject_iface.lpVtbl = &IDirectXFileEnumObject_Vtbl;
921     object->ref = 1;
922
923     *ppObj = object;
924     
925     return S_OK;
926 }
927
928 static inline IDirectXFileEnumObjectImpl *impl_from_IDirectXFileEnumObject(IDirectXFileEnumObject *iface)
929 {
930     return CONTAINING_RECORD(iface, IDirectXFileEnumObjectImpl, IDirectXFileEnumObject_iface);
931 }
932
933 /*** IUnknown methods ***/
934 static HRESULT WINAPI IDirectXFileEnumObjectImpl_QueryInterface(IDirectXFileEnumObject* iface, REFIID riid, void** ppvObject)
935 {
936   IDirectXFileEnumObjectImpl *This = impl_from_IDirectXFileEnumObject(iface);
937
938   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
939
940   if (IsEqualGUID(riid, &IID_IUnknown)
941       || IsEqualGUID(riid, &IID_IDirectXFileEnumObject))
942   {
943     IUnknown_AddRef(iface);
944     *ppvObject = &This->IDirectXFileEnumObject_iface;
945     return S_OK;
946   }
947
948   ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
949   return E_NOINTERFACE;
950 }
951
952 static ULONG WINAPI IDirectXFileEnumObjectImpl_AddRef(IDirectXFileEnumObject* iface)
953 {
954   IDirectXFileEnumObjectImpl *This = impl_from_IDirectXFileEnumObject(iface);
955   ULONG ref = InterlockedIncrement(&This->ref);
956
957   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
958
959   return ref;
960 }
961
962 static ULONG WINAPI IDirectXFileEnumObjectImpl_Release(IDirectXFileEnumObject* iface)
963 {
964   IDirectXFileEnumObjectImpl *This = impl_from_IDirectXFileEnumObject(iface);
965   ULONG ref = InterlockedDecrement(&This->ref);
966
967   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
968
969   if (!ref)
970   {
971     int i;
972     for (i = 0; i < This->nb_xobjects; i++)
973       IDirectXFileData_Release(This->pRefObjects[i]);
974     if (This->mapped_memory)
975       UnmapViewOfFile(This->mapped_memory);
976     HeapFree(GetProcessHeap(), 0, This->decomp_buffer);
977     HeapFree(GetProcessHeap(), 0, This);
978   }
979
980   return ref;
981 }
982
983 /*** IDirectXFileEnumObject methods ***/
984 static HRESULT WINAPI IDirectXFileEnumObjectImpl_GetNextDataObject(IDirectXFileEnumObject* iface, LPDIRECTXFILEDATA* ppDataObj)
985 {
986   IDirectXFileEnumObjectImpl *This = impl_from_IDirectXFileEnumObject(iface);
987   IDirectXFileDataImpl* object;
988   HRESULT hr;
989
990   TRACE("(%p/%p)->(%p)\n", This, iface, ppDataObj);
991
992   if (This->nb_xobjects >= MAX_OBJECTS)
993   {
994     ERR("Too many objects\n");
995     *ppDataObj = NULL;
996     return DXFILEERR_NOMOREOBJECTS;
997   }
998
999   /* Check if there are templates defined before the object */
1000   if (!parse_templates(&This->buf))
1001   {
1002     hr = DXFILEERR_BADVALUE;
1003     goto error;
1004   }
1005
1006   if (!This->buf.rem_bytes)
1007   {
1008     *ppDataObj = NULL;
1009     return DXFILEERR_NOMOREOBJECTS;
1010   }
1011
1012   hr = IDirectXFileDataImpl_Create(&object);
1013   if (FAILED(hr))
1014     return hr;
1015
1016   object->pobj = HeapAlloc(GetProcessHeap(), 0, sizeof(xobject)*MAX_SUBOBJECTS);
1017   if (!object->pobj)
1018   {
1019     ERR("Out of memory\n");
1020     hr = DXFILEERR_BADALLOC;
1021     goto error;
1022   }
1023
1024   object->pstrings = HeapAlloc(GetProcessHeap(), 0, MAX_STRINGS_BUFFER);
1025   if (!object->pstrings)
1026   {
1027     ERR("Out of memory\n");
1028     hr = DXFILEERR_BADALLOC;
1029     goto error;
1030   }
1031
1032   object->cur_enum_object = 0;
1033   object->level = 0;
1034   object->from_ref = FALSE;
1035
1036   This->buf.pxo_globals = This->xobjects;
1037   This->buf.nb_pxo_globals = This->nb_xobjects;
1038   This->buf.level = 0;
1039   This->buf.pdata = NULL;
1040   This->buf.capacity = 0;
1041   This->buf.cur_pos_data = 0;
1042   This->buf.cur_pstrings = This->buf.pstrings = object->pstrings;
1043   This->buf.pxo = This->xobjects[This->nb_xobjects] = This->buf.pxo_tab = object->pobj;
1044   This->buf.pxo->pdata = NULL;
1045   This->buf.pxo->nb_subobjects = 1;
1046
1047   if (!parse_object(&This->buf))
1048   {
1049     WARN("Object is not correct\n");
1050     hr = DXFILEERR_PARSEERROR;
1051     goto error;
1052   }
1053
1054   *ppDataObj = (LPDIRECTXFILEDATA)object;
1055
1056   /* Get a reference to created object */
1057   This->pRefObjects[This->nb_xobjects] = (LPDIRECTXFILEDATA)object;
1058   IDirectXFileData_AddRef(This->pRefObjects[This->nb_xobjects]);
1059
1060   This->nb_xobjects++;
1061
1062   return DXFILE_OK;
1063
1064 error:
1065
1066   IDirectXFileData_Release(&object->IDirectXFileData_iface);
1067   *ppDataObj = NULL;
1068
1069   return hr;
1070 }
1071
1072 static HRESULT WINAPI IDirectXFileEnumObjectImpl_GetDataObjectById(IDirectXFileEnumObject* iface, REFGUID rguid, LPDIRECTXFILEDATA* ppDataObj)
1073 {
1074   IDirectXFileEnumObjectImpl *This = impl_from_IDirectXFileEnumObject(iface);
1075
1076   FIXME("(%p/%p)->(%p,%p) stub!\n", This, iface, rguid, ppDataObj); 
1077
1078   return DXFILEERR_BADVALUE;
1079 }
1080
1081 static HRESULT WINAPI IDirectXFileEnumObjectImpl_GetDataObjectByName(IDirectXFileEnumObject* iface, LPCSTR szName, LPDIRECTXFILEDATA* ppDataObj)
1082 {
1083   IDirectXFileEnumObjectImpl *This = impl_from_IDirectXFileEnumObject(iface);
1084
1085   FIXME("(%p/%p)->(%s,%p) stub!\n", This, iface, szName, ppDataObj); 
1086
1087   return DXFILEERR_BADVALUE;
1088 }
1089
1090 static const IDirectXFileEnumObjectVtbl IDirectXFileEnumObject_Vtbl =
1091 {
1092     IDirectXFileEnumObjectImpl_QueryInterface,
1093     IDirectXFileEnumObjectImpl_AddRef,
1094     IDirectXFileEnumObjectImpl_Release,
1095     IDirectXFileEnumObjectImpl_GetNextDataObject,
1096     IDirectXFileEnumObjectImpl_GetDataObjectById,
1097     IDirectXFileEnumObjectImpl_GetDataObjectByName
1098 };
1099
1100 static HRESULT IDirectXFileSaveObjectImpl_Create(IDirectXFileSaveObjectImpl** ppObj)
1101 {
1102     IDirectXFileSaveObjectImpl* object;
1103
1104     TRACE("(%p)\n", ppObj);
1105
1106     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectXFileSaveObjectImpl));
1107     if (!object)
1108     {
1109         ERR("Out of memory\n");
1110         return DXFILEERR_BADALLOC;
1111     }
1112
1113     object->IDirectXFileSaveObject_iface.lpVtbl = &IDirectXFileSaveObject_Vtbl;
1114     object->ref = 1;
1115
1116     *ppObj = object;
1117
1118     return S_OK;
1119 }
1120
1121 static inline IDirectXFileSaveObjectImpl *impl_from_IDirectXFileSaveObject(IDirectXFileSaveObject *iface)
1122 {
1123     return CONTAINING_RECORD(iface, IDirectXFileSaveObjectImpl, IDirectXFileSaveObject_iface);
1124 }
1125
1126 /*** IUnknown methods ***/
1127 static HRESULT WINAPI IDirectXFileSaveObjectImpl_QueryInterface(IDirectXFileSaveObject* iface, REFIID riid, void** ppvObject)
1128 {
1129   IDirectXFileSaveObjectImpl *This = impl_from_IDirectXFileSaveObject(iface);
1130
1131   TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
1132
1133   if (IsEqualGUID(riid, &IID_IUnknown)
1134       || IsEqualGUID(riid, &IID_IDirectXFileSaveObject))
1135   {
1136     IUnknown_AddRef(iface);
1137     *ppvObject = &This->IDirectXFileSaveObject_iface;
1138     return S_OK;
1139   }
1140
1141   ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1142   return E_NOINTERFACE;
1143 }
1144
1145 static ULONG WINAPI IDirectXFileSaveObjectImpl_AddRef(IDirectXFileSaveObject* iface)
1146 {
1147   IDirectXFileSaveObjectImpl *This = impl_from_IDirectXFileSaveObject(iface);
1148   ULONG ref = InterlockedIncrement(&This->ref);
1149
1150   TRACE("(%p/%p): AddRef from %d\n", iface, This, ref - 1);
1151
1152   return ref;
1153 }
1154
1155 static ULONG WINAPI IDirectXFileSaveObjectImpl_Release(IDirectXFileSaveObject* iface)
1156 {
1157   IDirectXFileSaveObjectImpl *This = impl_from_IDirectXFileSaveObject(iface);
1158   ULONG ref = InterlockedDecrement(&This->ref);
1159
1160   TRACE("(%p/%p): ReleaseRef to %d\n", iface, This, ref);
1161
1162   if (!ref)
1163     HeapFree(GetProcessHeap(), 0, This);
1164
1165   return ref;
1166 }
1167
1168 static HRESULT WINAPI IDirectXFileSaveObjectImpl_SaveTemplates(IDirectXFileSaveObject* iface, DWORD cTemplates, const GUID** ppguidTemplates)
1169 {
1170   IDirectXFileSaveObjectImpl *This = impl_from_IDirectXFileSaveObject(iface);
1171
1172   FIXME("(%p/%p)->(%d,%p) stub!\n", This, iface, cTemplates, ppguidTemplates);
1173
1174   return DXFILE_OK;
1175 }
1176
1177 static HRESULT WINAPI IDirectXFileSaveObjectImpl_CreateDataObject(IDirectXFileSaveObject* iface, REFGUID rguidTemplate, LPCSTR szName, const GUID* pguid, DWORD cbSize, LPVOID pvData, LPDIRECTXFILEDATA* ppDataObj)
1178 {
1179   IDirectXFileSaveObjectImpl *This = impl_from_IDirectXFileSaveObject(iface);
1180
1181   FIXME("(%p/%p)->(%p,%s,%p,%d,%p,%p) stub!\n", This, iface, rguidTemplate, szName, pguid, cbSize, pvData, ppDataObj);
1182
1183   return DXFILEERR_BADVALUE;
1184 }
1185
1186 static HRESULT WINAPI IDirectXFileSaveObjectImpl_SaveData(IDirectXFileSaveObject* iface, LPDIRECTXFILEDATA ppDataObj)
1187 {
1188   IDirectXFileSaveObjectImpl *This = impl_from_IDirectXFileSaveObject(iface);
1189
1190   FIXME("(%p/%p)->(%p) stub!\n", This, iface, ppDataObj); 
1191
1192   return DXFILEERR_BADVALUE;
1193 }
1194
1195 static const IDirectXFileSaveObjectVtbl IDirectXFileSaveObject_Vtbl =
1196 {
1197     IDirectXFileSaveObjectImpl_QueryInterface,
1198     IDirectXFileSaveObjectImpl_AddRef,
1199     IDirectXFileSaveObjectImpl_Release,
1200     IDirectXFileSaveObjectImpl_SaveTemplates,
1201     IDirectXFileSaveObjectImpl_CreateDataObject,
1202     IDirectXFileSaveObjectImpl_SaveData
1203 };