d3dx9: Specify arguments in trace to ease debugging.
[wine] / dlls / d3dx9_36 / xfile.c
1 /*
2  * Copyright (C) 2012 Christian Costa
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  *
18  */
19
20 #include "wine/debug.h"
21
22 #include "d3dx9.h"
23 #include "d3dx9xof.h"
24 #undef MAKE_DDHRESULT
25 #include "dxfile.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
28
29 static HRESULT error_dxfile_to_d3dxfile(HRESULT error)
30 {
31     switch (error)
32     {
33         case DXFILEERR_BADFILETYPE:
34             return D3DXFERR_BADFILETYPE;
35         case DXFILEERR_BADFILEVERSION:
36             return D3DXFERR_BADFILEVERSION;
37         case DXFILEERR_BADFILEFLOATSIZE:
38             return D3DXFERR_BADFILEFLOATSIZE;
39         case DXFILEERR_PARSEERROR:
40             return D3DXFERR_PARSEERROR;
41         default:
42             FIXME("Cannot map error %#x\n", error);
43             return E_FAIL;
44     }
45 }
46
47 typedef struct {
48     ID3DXFile ID3DXFile_iface;
49     LONG ref;
50     IDirectXFile *dxfile;
51 } ID3DXFileImpl;
52
53 typedef struct {
54     ID3DXFileEnumObject ID3DXFileEnumObject_iface;
55     LONG ref;
56     ULONG nb_children;
57     ID3DXFileData **children;
58 } ID3DXFileEnumObjectImpl;
59
60 typedef struct {
61     ID3DXFileData ID3DXFileData_iface;
62     LONG ref;
63     BOOL reference;
64     IDirectXFileData *dxfile_data;
65     ULONG nb_children;
66     ID3DXFileData **children;
67 } ID3DXFileDataImpl;
68
69
70 static inline ID3DXFileImpl* impl_from_ID3DXFile(ID3DXFile *iface)
71 {
72     return CONTAINING_RECORD(iface, ID3DXFileImpl, ID3DXFile_iface);
73 }
74
75 static inline ID3DXFileEnumObjectImpl* impl_from_ID3DXFileEnumObject(ID3DXFileEnumObject *iface)
76 {
77     return CONTAINING_RECORD(iface, ID3DXFileEnumObjectImpl, ID3DXFileEnumObject_iface);
78 }
79
80 static inline ID3DXFileDataImpl* impl_from_ID3DXFileData(ID3DXFileData *iface)
81 {
82     return CONTAINING_RECORD(iface, ID3DXFileDataImpl, ID3DXFileData_iface);
83 }
84
85 /*** IUnknown methods ***/
86
87 static HRESULT WINAPI ID3DXFileDataImpl_QueryInterface(ID3DXFileData *iface, REFIID riid, void **ret_iface)
88 {
89     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ret_iface);
90
91     if (IsEqualGUID(riid, &IID_IUnknown) ||
92         IsEqualGUID(riid, &IID_ID3DXFileData))
93     {
94         iface->lpVtbl->AddRef(iface);
95         *ret_iface = iface;
96         return S_OK;
97     }
98
99     WARN("(%p)->(%s, %p), not found\n", iface, debugstr_guid(riid), ret_iface);
100     *ret_iface = NULL;
101     return E_NOINTERFACE;
102 }
103
104 static ULONG WINAPI ID3DXFileDataImpl_AddRef(ID3DXFileData *iface)
105 {
106     ID3DXFileDataImpl *This = impl_from_ID3DXFileData(iface);
107     ULONG ref = InterlockedIncrement(&This->ref);
108
109     TRACE("(%p)->(): new ref = %u\n", iface, ref);
110
111     return ref;
112 }
113
114 static ULONG WINAPI ID3DXFileDataImpl_Release(ID3DXFileData *iface)
115 {
116     ID3DXFileDataImpl *This = impl_from_ID3DXFileData(iface);
117     ULONG ref = InterlockedDecrement(&This->ref);
118
119     TRACE("(%p)->(): new ref = %u\n", iface, ref);
120
121     if (!ref)
122     {
123         ULONG i;
124
125         for (i = 0; i < This->nb_children; i++)
126             (This->children[i])->lpVtbl->Release(This->children[i]);
127         HeapFree(GetProcessHeap(), 0, This->children);
128         IDirectXFileData_Release(This->dxfile_data);
129         HeapFree(GetProcessHeap(), 0, This);
130     }
131
132     return ref;
133 }
134
135
136 /*** ID3DXFileData methods ***/
137
138 static HRESULT WINAPI ID3DXFileDataImpl_GetEnum(ID3DXFileData *iface, ID3DXFileEnumObject **enum_object)
139 {
140     FIXME("(%p)->(%p): stub\n", iface, enum_object);
141
142     return E_NOTIMPL;
143 }
144
145
146 static HRESULT WINAPI ID3DXFileDataImpl_GetName(ID3DXFileData *iface, char *name, SIZE_T *size)
147 {
148     ID3DXFileDataImpl *This = impl_from_ID3DXFileData(iface);
149     DWORD dxfile_size;
150     HRESULT ret;
151
152     TRACE("(%p)->(%p, %p)\n", iface, name, size);
153
154     if (!name || !size)
155         return E_POINTER;
156
157     dxfile_size = *size;
158
159     ret = IDirectXFileData_GetName(This->dxfile_data, name, &dxfile_size);
160     if (ret != DXFILE_OK)
161         return error_dxfile_to_d3dxfile(ret);
162
163     *size = dxfile_size;
164
165     return S_OK;
166 }
167
168
169 static HRESULT WINAPI ID3DXFileDataImpl_GetId(ID3DXFileData *iface, GUID *guid)
170 {
171     ID3DXFileDataImpl *This = impl_from_ID3DXFileData(iface);
172     HRESULT ret;
173
174     TRACE("(%p)->(%p)\n", iface, guid);
175
176     if (!guid)
177         return E_POINTER;
178
179     ret = IDirectXFileData_GetId(This->dxfile_data, guid);
180     if (ret != DXFILE_OK)
181         return error_dxfile_to_d3dxfile(ret);
182
183     return S_OK;
184 }
185
186
187 static HRESULT WINAPI ID3DXFileDataImpl_Lock(ID3DXFileData *iface, SIZE_T *size, const void **data)
188 {
189     ID3DXFileDataImpl *This = impl_from_ID3DXFileData(iface);
190     DWORD dxfile_size;
191     HRESULT ret;
192
193     TRACE("(%p)->(%p, %p)\n", iface, size, data);
194
195     if (!size || !data)
196         return E_POINTER;
197
198     ret = IDirectXFileData_GetData(This->dxfile_data, NULL, &dxfile_size, (void**)data);
199     if (ret != DXFILE_OK)
200         return error_dxfile_to_d3dxfile(ret);
201
202     *size = dxfile_size;
203
204     return S_OK;
205 }
206
207
208 static HRESULT WINAPI ID3DXFileDataImpl_Unlock(ID3DXFileData *iface)
209 {
210     TRACE("(%p)->()\n", iface);
211
212     /* Nothing to do */
213
214     return S_OK;
215 }
216
217
218 static HRESULT WINAPI ID3DXFileDataImpl_GetType(ID3DXFileData *iface, GUID *guid)
219 {
220     ID3DXFileDataImpl *This = impl_from_ID3DXFileData(iface);
221     const GUID *dxfile_guid;
222     HRESULT ret;
223
224     TRACE("(%p)->(%p)\n", iface, guid);
225
226     ret = IDirectXFileData_GetType(This->dxfile_data, &dxfile_guid);
227     if (ret != DXFILE_OK)
228         return error_dxfile_to_d3dxfile(ret);
229
230     *guid = *dxfile_guid;
231
232     return S_OK;
233 }
234
235
236 static BOOL WINAPI ID3DXFileDataImpl_IsReference(ID3DXFileData *iface)
237 {
238     ID3DXFileDataImpl *This = impl_from_ID3DXFileData(iface);
239
240     TRACE("(%p)->()\n", iface);
241
242     return This->reference;
243 }
244
245
246 static HRESULT WINAPI ID3DXFileDataImpl_GetChildren(ID3DXFileData *iface, SIZE_T *children)
247 {
248     ID3DXFileDataImpl *This = impl_from_ID3DXFileData(iface);
249
250     TRACE("(%p)->(%p)\n", iface, children);
251
252     if (!children)
253         return E_POINTER;
254
255     *children = This->nb_children;
256
257     return S_OK;
258 }
259
260
261 static HRESULT WINAPI ID3DXFileDataImpl_GetChild(ID3DXFileData *iface, SIZE_T id, ID3DXFileData **object)
262 {
263     ID3DXFileDataImpl *This = impl_from_ID3DXFileData(iface);
264
265     TRACE("(%p)->(%lu, %p)\n", iface, id, object);
266
267     if (!object)
268         return E_POINTER;
269
270     *object = This->children[id];
271     (*object)->lpVtbl->AddRef(*object);
272
273     return S_OK;
274 }
275
276
277 static const ID3DXFileDataVtbl ID3DXFileData_Vtbl =
278 {
279     ID3DXFileDataImpl_QueryInterface,
280     ID3DXFileDataImpl_AddRef,
281     ID3DXFileDataImpl_Release,
282     ID3DXFileDataImpl_GetEnum,
283     ID3DXFileDataImpl_GetName,
284     ID3DXFileDataImpl_GetId,
285     ID3DXFileDataImpl_Lock,
286     ID3DXFileDataImpl_Unlock,
287     ID3DXFileDataImpl_GetType,
288     ID3DXFileDataImpl_IsReference,
289     ID3DXFileDataImpl_GetChildren,
290     ID3DXFileDataImpl_GetChild
291 };
292
293
294 static HRESULT ID3DXFileDataImpl_Create(IDirectXFileObject *dxfile_object, ID3DXFileData **ret_iface)
295 {
296     ID3DXFileDataImpl *object;
297     IDirectXFileObject *data_object;
298     HRESULT ret;
299
300     TRACE("(%p, %p)\n", dxfile_object, ret_iface);
301
302     *ret_iface = NULL;
303
304     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
305     if (!object)
306         return E_OUTOFMEMORY;
307
308     object->ID3DXFileData_iface.lpVtbl = &ID3DXFileData_Vtbl;
309     object->ref = 1;
310
311     ret = IDirectXFileObject_QueryInterface(dxfile_object, &IID_IDirectXFileData, (void **)&object->dxfile_data);
312     if (FAILED(ret))
313     {
314         IDirectXFileDataReference *reference;
315
316         ret = IDirectXFileObject_QueryInterface(dxfile_object, &IID_IDirectXFileDataReference, (void **)&reference);
317         if (SUCCEEDED(ret))
318         {
319             ret = IDirectXFileDataReference_Resolve(reference, &object->dxfile_data);
320             if (FAILED(ret))
321             {
322                 HeapFree(GetProcessHeap(), 0, object);
323                 return E_FAIL;
324             }
325             object->reference = TRUE;
326         }
327         else
328         {
329             FIXME("Don't known what to do with binary object\n");
330             HeapFree(GetProcessHeap(), 0, object);
331             return E_FAIL;
332         }
333     }
334
335     while (SUCCEEDED(ret = IDirectXFileData_GetNextObject(object->dxfile_data, &data_object)))
336     {
337         if (object->children)
338             object->children = HeapReAlloc(GetProcessHeap(), 0, object->children, sizeof(ID3DXFileData*) * (object->nb_children + 1));
339         else
340             object->children = HeapAlloc(GetProcessHeap(), 0, sizeof(ID3DXFileData*));
341         if (!object->children)
342         {
343             ret = E_OUTOFMEMORY;
344             break;
345         }
346         ret = ID3DXFileDataImpl_Create(data_object, &object->children[object->nb_children]);
347         if (ret != S_OK)
348             break;
349         object->nb_children++;
350     }
351
352     if (ret != DXFILEERR_NOMOREOBJECTS)
353     {
354         (&object->ID3DXFileData_iface)->lpVtbl->Release(&object->ID3DXFileData_iface);
355         return ret;
356     }
357
358     TRACE("Found %u children\n", object->nb_children);
359
360     *ret_iface = &object->ID3DXFileData_iface;
361
362     return S_OK;
363 }
364
365
366 /*** IUnknown methods ***/
367
368 static HRESULT WINAPI ID3DXFileEnumObjectImpl_QueryInterface(ID3DXFileEnumObject *iface, REFIID riid, void **ret_iface)
369 {
370     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ret_iface);
371
372     if (IsEqualGUID(riid, &IID_IUnknown) ||
373         IsEqualGUID(riid, &IID_ID3DXFileEnumObject))
374     {
375         iface->lpVtbl->AddRef(iface);
376         *ret_iface = iface;
377         return S_OK;
378     }
379
380     WARN("(%p)->(%s, %p), not found\n", iface, debugstr_guid(riid), ret_iface);
381     *ret_iface = NULL;
382     return E_NOINTERFACE;
383 }
384
385 static ULONG WINAPI ID3DXFileEnumObjectImpl_AddRef(ID3DXFileEnumObject *iface)
386 {
387     ID3DXFileEnumObjectImpl *This = impl_from_ID3DXFileEnumObject(iface);
388     ULONG ref = InterlockedIncrement(&This->ref);
389
390     TRACE("(%p)->(): new ref = %u\n", iface, ref);
391
392     return ref;
393 }
394
395 static ULONG WINAPI ID3DXFileEnumObjectImpl_Release(ID3DXFileEnumObject *iface)
396 {
397     ID3DXFileEnumObjectImpl *This = impl_from_ID3DXFileEnumObject(iface);
398     ULONG ref = InterlockedDecrement(&This->ref);
399
400     TRACE("(%p)->(): new ref = %u\n", iface, ref);
401
402     if (!ref)
403     {
404         ULONG i;
405
406         for (i = 0; i < This->nb_children; i++)
407             (This->children[i])->lpVtbl->Release(This->children[i]);
408         HeapFree(GetProcessHeap(), 0, This->children);
409         HeapFree(GetProcessHeap(), 0, This);
410     }
411
412     return ref;
413 }
414
415
416 /*** ID3DXFileEnumObject methods ***/
417
418 static HRESULT WINAPI ID3DXFileEnumObjectImpl_GetFile(ID3DXFileEnumObject *iface, ID3DXFile **file)
419 {
420     FIXME("(%p)->(%p): stub\n", iface, file);
421
422     return E_NOTIMPL;
423 }
424
425
426 static HRESULT WINAPI ID3DXFileEnumObjectImpl_GetChildren(ID3DXFileEnumObject *iface, SIZE_T *children)
427 {
428     ID3DXFileEnumObjectImpl *This = impl_from_ID3DXFileEnumObject(iface);
429
430     TRACE("(%p)->(%p)\n", iface, children);
431
432     if (!children)
433         return E_POINTER;
434
435     *children = This->nb_children;
436
437     return S_OK;
438 }
439
440
441 static HRESULT WINAPI ID3DXFileEnumObjectImpl_GetChild(ID3DXFileEnumObject *iface, SIZE_T id, ID3DXFileData **object)
442 {
443     ID3DXFileEnumObjectImpl *This = impl_from_ID3DXFileEnumObject(iface);
444
445     TRACE("(%p)->(%lu, %p)\n", iface, id, object);
446
447     if (!object)
448         return E_POINTER;
449
450     *object = This->children[id];
451     (*object)->lpVtbl->AddRef(*object);
452
453     return S_OK;
454 }
455
456
457 static HRESULT WINAPI ID3DXFileEnumObjectImpl_GetDataObjectById(ID3DXFileEnumObject *iface, REFGUID guid, ID3DXFileData **object)
458 {
459     FIXME("(%p)->(%s, %p): stub\n", iface, debugstr_guid(guid), object);
460
461     return E_NOTIMPL;
462 }
463
464
465 static HRESULT WINAPI ID3DXFileEnumObjectImpl_GetDataObjectByName(ID3DXFileEnumObject *iface, const char *name, ID3DXFileData **object)
466 {
467     FIXME("(%p)->(%s, %p): stub\n", iface, debugstr_a(name), object);
468
469     return E_NOTIMPL;
470 }
471
472
473 static const ID3DXFileEnumObjectVtbl ID3DXFileEnumObject_Vtbl =
474 {
475     ID3DXFileEnumObjectImpl_QueryInterface,
476     ID3DXFileEnumObjectImpl_AddRef,
477     ID3DXFileEnumObjectImpl_Release,
478     ID3DXFileEnumObjectImpl_GetFile,
479     ID3DXFileEnumObjectImpl_GetChildren,
480     ID3DXFileEnumObjectImpl_GetChild,
481     ID3DXFileEnumObjectImpl_GetDataObjectById,
482     ID3DXFileEnumObjectImpl_GetDataObjectByName
483 };
484
485
486 /*** IUnknown methods ***/
487
488 static HRESULT WINAPI ID3DXFileImpl_QueryInterface(ID3DXFile *iface, REFIID riid, void **ret_iface)
489 {
490     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ret_iface);
491
492     if (IsEqualGUID(riid, &IID_IUnknown) ||
493         IsEqualGUID(riid, &IID_ID3DXFile))
494     {
495         iface->lpVtbl->AddRef(iface);
496         *ret_iface = iface;
497         return S_OK;
498     }
499
500     WARN("(%p)->(%s, %p), not found\n", iface, debugstr_guid(riid), ret_iface);
501     *ret_iface = NULL;
502     return E_NOINTERFACE;
503 }
504
505
506 static ULONG WINAPI ID3DXFileImpl_AddRef(ID3DXFile *iface)
507 {
508     ID3DXFileImpl *This = impl_from_ID3DXFile(iface);
509     ULONG ref = InterlockedIncrement(&This->ref);
510
511     TRACE("(%p)->(): new ref = %u\n", iface, ref);
512
513     return ref;
514 }
515
516
517 static ULONG WINAPI ID3DXFileImpl_Release(ID3DXFile *iface)
518 {
519     ID3DXFileImpl *This = impl_from_ID3DXFile(iface);
520     ULONG ref = InterlockedDecrement(&This->ref);
521
522     TRACE("(%p)->(): new ref = %u\n", iface, ref);
523
524     if (!ref)
525     {
526         IDirectXFile_Release(This->dxfile);
527         HeapFree(GetProcessHeap(), 0, This);
528     }
529
530     return ref;
531 }
532
533
534 /*** ID3DXFile methods ***/
535
536 static HRESULT WINAPI ID3DXFileImpl_CreateEnumObject(ID3DXFile *iface, const void *source, D3DXF_FILELOADOPTIONS options, ID3DXFileEnumObject **enum_object)
537 {
538     ID3DXFileImpl *This = impl_from_ID3DXFile(iface);
539     ID3DXFileEnumObjectImpl *object;
540     IDirectXFileEnumObject *dxfile_enum_object;
541     void *dxfile_source;
542     DXFILELOADOPTIONS dxfile_options;
543     DXFILELOADRESOURCE dxfile_resource;
544     DXFILELOADMEMORY dxfile_memory;
545     IDirectXFileData *data_object;
546     HRESULT ret;
547
548     TRACE("(%p)->(%p, %x, %p)\n", iface, source, options, enum_object);
549
550     if (!enum_object)
551         return E_POINTER;
552
553     *enum_object = NULL;
554
555     if (options == D3DXF_FILELOAD_FROMFILE)
556     {
557         dxfile_source = (void*)source;
558         dxfile_options = DXFILELOAD_FROMFILE;
559     }
560     else if (options == D3DXF_FILELOAD_FROMRESOURCE)
561     {
562         D3DXF_FILELOADRESOURCE *resource = (D3DXF_FILELOADRESOURCE*)source;
563
564         dxfile_resource.hModule = resource->hModule;
565         dxfile_resource.lpName = resource->lpName;
566         dxfile_resource.lpType = resource->lpType;
567         dxfile_source = &dxfile_resource;
568         dxfile_options = DXFILELOAD_FROMRESOURCE;
569     }
570     else if (options == D3DXF_FILELOAD_FROMMEMORY)
571     {
572         D3DXF_FILELOADMEMORY *memory = (D3DXF_FILELOADMEMORY*)source;
573
574         dxfile_memory.lpMemory = memory->lpMemory;
575         dxfile_memory.dSize = memory->dSize;
576         dxfile_source = &dxfile_memory;
577         dxfile_options = DXFILELOAD_FROMMEMORY;
578     }
579     else
580     {
581         FIXME("Source type %u is not handled yet\n", options);
582         return E_NOTIMPL;
583     }
584
585     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
586     if (!object)
587         return E_OUTOFMEMORY;
588
589     object->ID3DXFileEnumObject_iface.lpVtbl = &ID3DXFileEnumObject_Vtbl;
590     object->ref = 1;
591
592     ret = IDirectXFile_CreateEnumObject(This->dxfile, dxfile_source, dxfile_options, &dxfile_enum_object);
593
594     if (ret != S_OK)
595     {
596         HeapFree(GetProcessHeap(), 0, object);
597         return ret;
598     }
599
600     /* Fill enum object with top level data objects */
601     while (SUCCEEDED(ret = IDirectXFileEnumObject_GetNextDataObject(dxfile_enum_object, &data_object)))
602     {
603         if (object->children)
604             object->children = HeapReAlloc(GetProcessHeap(), 0, object->children, sizeof(*object->children) * (object->nb_children + 1));
605         else
606             object->children = HeapAlloc(GetProcessHeap(), 0, sizeof(*object->children));
607         if (!object->children)
608         {
609             ret = E_OUTOFMEMORY;
610             break;
611         }
612         ret = ID3DXFileDataImpl_Create((IDirectXFileObject*)data_object, &object->children[object->nb_children]);
613         if (ret != S_OK)
614             break;
615         object->nb_children++;
616     }
617
618     IDirectXFileEnumObject_Release(dxfile_enum_object);
619
620     if (ret != DXFILEERR_NOMOREOBJECTS)
621         WARN("Cannot get all top level data objects\n");
622
623     TRACE("Found %u children\n", object->nb_children);
624
625     *enum_object = &object->ID3DXFileEnumObject_iface;
626
627     return S_OK;
628 }
629
630
631 static HRESULT WINAPI ID3DXFileImpl_CreateSaveObject(ID3DXFile *iface, const void *data, D3DXF_FILESAVEOPTIONS options, D3DXF_FILEFORMAT format, ID3DXFileSaveObject **save_object)
632 {
633     FIXME("(%p)->(%p, %x, %u, %p): stub\n", iface, data, options, format, save_object);
634
635     return E_NOTIMPL;
636 }
637
638
639 static HRESULT WINAPI ID3DXFileImpl_RegisterTemplates(ID3DXFile *iface, const void *data, SIZE_T size)
640 {
641     ID3DXFileImpl *This = impl_from_ID3DXFile(iface);
642     HRESULT ret;
643
644     TRACE("(%p)->(%p, %lu)\n", iface, data, size);
645
646     ret = IDirectXFile_RegisterTemplates(This->dxfile, (void*)data, size);
647     if (ret != DXFILE_OK)
648     {
649         WARN("Error %#x\n", ret);
650         return error_dxfile_to_d3dxfile(ret);
651     }
652
653     return S_OK;
654 }
655
656
657 static HRESULT WINAPI ID3DXFileImpl_RegisterEnumTemplates(ID3DXFile *iface, ID3DXFileEnumObject *enum_object)
658 {
659     FIXME("(%p)->(%p): stub\n", iface, enum_object);
660
661     return E_NOTIMPL;
662 }
663
664
665 static const ID3DXFileVtbl ID3DXFile_Vtbl =
666 {
667     ID3DXFileImpl_QueryInterface,
668     ID3DXFileImpl_AddRef,
669     ID3DXFileImpl_Release,
670     ID3DXFileImpl_CreateEnumObject,
671     ID3DXFileImpl_CreateSaveObject,
672     ID3DXFileImpl_RegisterTemplates,
673     ID3DXFileImpl_RegisterEnumTemplates
674 };
675
676 HRESULT WINAPI D3DXFileCreate(ID3DXFile **d3dxfile)
677 {
678     ID3DXFileImpl *object;
679     HRESULT ret;
680
681     TRACE("(%p)\n", d3dxfile);
682
683     if (!d3dxfile)
684         return E_POINTER;
685
686     *d3dxfile = NULL;
687
688     object = HeapAlloc(GetProcessHeap(), 0, sizeof(*object));
689     if (!object)
690         return E_OUTOFMEMORY;
691
692     ret = DirectXFileCreate(&object->dxfile);
693     if (ret != S_OK)
694     {
695         HeapFree(GetProcessHeap(), 0, object);
696         if (ret == E_OUTOFMEMORY)
697             return ret;
698         return E_FAIL;
699     }
700
701     object->ID3DXFile_iface.lpVtbl = &ID3DXFile_Vtbl;
702     object->ref = 1;
703
704     *d3dxfile = &object->ID3DXFile_iface;
705
706     return S_OK;
707 }