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