mfplat/sample: Optimize copying to 2d buffer.
[wine.git] / dlls / dmband / bandtrack.c
blobf2a40c217515ec6e2fb892014eb90d3acb3833d4
1 /*
2 * Copyright (C) 2003-2004 Rok Mandeljc
4 * This program 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.
9 * This program 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.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "dmband_private.h"
20 #include "dmobject.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(dmband);
24 struct band_entry
26 struct list entry;
27 DMUS_IO_BAND_ITEM_HEADER2 head;
28 IDirectMusicBand *band;
31 static void band_entry_destroy(struct band_entry *entry)
33 IDirectMusicTrack_Release(entry->band);
34 free(entry);
37 struct band_track
39 IDirectMusicTrack8 IDirectMusicTrack8_iface;
40 struct dmobject dmobj; /* IPersistStream only */
41 LONG ref;
42 DMUS_IO_BAND_TRACK_HEADER header;
43 struct list bands;
46 static inline struct band_track *impl_from_IDirectMusicTrack8(IDirectMusicTrack8 *iface)
48 return CONTAINING_RECORD(iface, struct band_track, IDirectMusicTrack8_iface);
51 static HRESULT WINAPI band_track_QueryInterface(IDirectMusicTrack8 *iface, REFIID riid,
52 void **ret_iface)
54 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
56 TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface);
58 *ret_iface = NULL;
60 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicTrack) ||
61 IsEqualIID(riid, &IID_IDirectMusicTrack8))
62 *ret_iface = iface;
63 else if (IsEqualIID(riid, &IID_IPersistStream))
64 *ret_iface = &This->dmobj.IPersistStream_iface;
65 else {
66 WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ret_iface);
67 return E_NOINTERFACE;
70 IUnknown_AddRef((IUnknown*)*ret_iface);
71 return S_OK;
74 static ULONG WINAPI band_track_AddRef(IDirectMusicTrack8 *iface)
76 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
77 LONG ref = InterlockedIncrement(&This->ref);
79 TRACE("(%p) ref=%ld\n", This, ref);
81 return ref;
84 static ULONG WINAPI band_track_Release(IDirectMusicTrack8 *iface)
86 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
87 LONG ref = InterlockedDecrement(&This->ref);
89 TRACE("(%p) ref=%ld\n", This, ref);
91 if (!ref)
93 struct band_entry *entry, *next;
95 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &This->bands, struct band_entry, entry)
97 list_remove(&entry->entry);
98 band_entry_destroy(entry);
101 free(This);
104 return ref;
107 static HRESULT WINAPI band_track_Init(IDirectMusicTrack8 *iface, IDirectMusicSegment *segment)
109 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
111 FIXME("(%p, %p): stub\n", This, segment);
113 if (!segment) return E_POINTER;
114 return S_OK;
117 static HRESULT WINAPI band_track_InitPlay(IDirectMusicTrack8 *iface,
118 IDirectMusicSegmentState *segment_state, IDirectMusicPerformance *performance,
119 void **state_data, DWORD virtual_track8id, DWORD flags)
121 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
122 struct band_entry *entry;
123 HRESULT hr;
125 FIXME("(%p, %p, %p, %p, %ld, %lx): semi-stub\n", This, segment_state, performance, state_data, virtual_track8id, flags);
127 if (!performance) return E_POINTER;
129 if (This->header.bAutoDownload)
131 LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry)
133 if (FAILED(hr = IDirectMusicBand_Download(entry->band, performance)))
134 return hr;
138 return S_OK;
141 static HRESULT WINAPI band_track_EndPlay(IDirectMusicTrack8 *iface, void *state_data)
143 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
144 struct band_entry *entry;
145 HRESULT hr;
147 FIXME("(%p, %p): semi-stub\n", This, state_data);
149 if (This->header.bAutoDownload)
151 LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry)
153 if (FAILED(hr = IDirectMusicBand_Unload(entry->band, NULL)))
154 return hr;
158 return S_OK;
161 static HRESULT WINAPI band_track_Play(IDirectMusicTrack8 *iface, void *state_data,
162 MUSIC_TIME start_time, MUSIC_TIME end_time, MUSIC_TIME time_offset, DWORD segment_flags,
163 IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state, DWORD track_id)
165 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
166 IDirectMusicGraph *graph;
167 struct band_entry *entry;
168 HRESULT hr;
170 TRACE("(%p, %p, %ld, %ld, %ld, %#lx, %p, %p, %ld)\n", This, state_data, start_time, end_time,
171 time_offset, segment_flags, performance, segment_state, track_id);
173 if (!performance) return DMUS_S_END;
175 if (start_time != 0) FIXME("start_time %ld not implemented\n", start_time);
176 if (end_time != -1) FIXME("end_time %ld not implemented\n", end_time);
177 if (segment_flags) FIXME("segment_flags %#lx not implemented\n", segment_flags);
178 if (segment_state) FIXME("segment_state %p not implemented\n", segment_state);
180 if (FAILED(hr = IDirectMusicPerformance_QueryInterface(performance,
181 &IID_IDirectMusicGraph, (void **)&graph)))
182 return hr;
184 LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry)
186 MUSIC_TIME music_time = entry->head.lBandTimeLogical;
187 if (music_time != -1) music_time += time_offset;
188 if (FAILED(hr = band_send_messages(entry->band, performance, graph, music_time, track_id)))
189 break;
192 IDirectMusicGraph_Release(graph);
193 return hr;
196 static HRESULT WINAPI band_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time,
197 MUSIC_TIME *next, void *param)
199 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
201 TRACE("(%p, %s, %ld, %p, %p)\n", This, debugstr_dmguid(type), time, next, param);
203 if (!type)
204 return E_POINTER;
205 if (!IsEqualGUID(type, &GUID_BandParam))
206 return DMUS_E_GET_UNSUPPORTED;
208 FIXME("GUID_BandParam not handled yet\n");
210 return S_OK;
213 static HRESULT WINAPI band_track_SetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time,
214 void *param)
216 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
218 TRACE("(%p, %s, %ld, %p)\n", This, debugstr_dmguid(type), time, param);
220 if (!type)
221 return E_POINTER;
222 if (FAILED(IDirectMusicTrack8_IsParamSupported(iface, type)))
223 return DMUS_E_TYPE_UNSUPPORTED;
225 if (IsEqualGUID(type, &GUID_BandParam))
226 FIXME("GUID_BandParam not handled yet\n");
227 else if (IsEqualGUID(type, &GUID_Clear_All_Bands))
228 FIXME("GUID_Clear_All_Bands not handled yet\n");
229 else if (IsEqualGUID(type, &GUID_ConnectToDLSCollection))
231 struct band_entry *entry;
233 LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry)
234 band_connect_to_collection(entry->band, param);
236 else if (IsEqualGUID(type, &GUID_Disable_Auto_Download))
237 This->header.bAutoDownload = FALSE;
238 else if (IsEqualGUID(type, &GUID_Download))
239 FIXME("GUID_Download not handled yet\n");
240 else if (IsEqualGUID(type, &GUID_DownloadToAudioPath))
242 IDirectMusicPerformance *performance;
243 IDirectMusicAudioPath *audio_path;
244 IUnknown *object = param;
245 struct band_entry *entry;
246 HRESULT hr;
248 if (FAILED(hr = IDirectMusicAudioPath_QueryInterface(object, &IID_IDirectMusicPerformance8, (void **)&performance))
249 && SUCCEEDED(hr = IDirectMusicAudioPath_QueryInterface(object, &IID_IDirectMusicAudioPath, (void **)&audio_path)))
251 hr = IDirectMusicAudioPath_GetObjectInPath(audio_path, DMUS_PCHANNEL_ALL, DMUS_PATH_PERFORMANCE, 0,
252 &GUID_All_Objects, 0, &IID_IDirectMusicPerformance8, (void **)&performance);
253 IDirectMusicAudioPath_Release(audio_path);
256 if (FAILED(hr))
258 WARN("Failed to get IDirectMusicPerformance from param %p\n", param);
259 return hr;
262 LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry)
263 if (FAILED(hr = IDirectMusicBand_Download(entry->band, performance))) break;
265 IDirectMusicPerformance_Release(performance);
267 else if (IsEqualGUID(type, &GUID_Enable_Auto_Download))
268 This->header.bAutoDownload = TRUE;
269 else if (IsEqualGUID(type, &GUID_IDirectMusicBand))
270 FIXME("GUID_IDirectMusicBand not handled yet\n");
271 else if (IsEqualGUID(type, &GUID_StandardMIDIFile))
272 FIXME("GUID_StandardMIDIFile not handled yet\n");
273 else if (IsEqualGUID(type, &GUID_UnloadFromAudioPath))
275 struct band_entry *entry;
276 HRESULT hr;
278 LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry)
279 if (FAILED(hr = IDirectMusicBand_Unload(entry->band, NULL))) break;
282 return S_OK;
285 static HRESULT WINAPI band_track_IsParamSupported(IDirectMusicTrack8 *iface, REFGUID rguidType)
287 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
289 TRACE("(%p, %s)\n", This, debugstr_dmguid(rguidType));
291 if (!rguidType)
292 return E_POINTER;
294 if (IsEqualGUID (rguidType, &GUID_BandParam)
295 || IsEqualGUID (rguidType, &GUID_Clear_All_Bands)
296 || IsEqualGUID (rguidType, &GUID_ConnectToDLSCollection)
297 || IsEqualGUID (rguidType, &GUID_Disable_Auto_Download)
298 || IsEqualGUID (rguidType, &GUID_Download)
299 || IsEqualGUID (rguidType, &GUID_DownloadToAudioPath)
300 || IsEqualGUID (rguidType, &GUID_Enable_Auto_Download)
301 || IsEqualGUID (rguidType, &GUID_IDirectMusicBand)
302 || IsEqualGUID (rguidType, &GUID_StandardMIDIFile)
303 || IsEqualGUID (rguidType, &GUID_Unload)
304 || IsEqualGUID (rguidType, &GUID_UnloadFromAudioPath)) {
305 TRACE("param supported\n");
306 return S_OK;
309 TRACE("param unsupported\n");
310 return DMUS_E_TYPE_UNSUPPORTED;
313 static HRESULT WINAPI band_track_AddNotificationType(IDirectMusicTrack8 *iface, REFGUID notiftype)
315 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
317 TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype));
318 return E_NOTIMPL;
321 static HRESULT WINAPI band_track_RemoveNotificationType(IDirectMusicTrack8 *iface,
322 REFGUID notiftype)
324 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
326 TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype));
327 return E_NOTIMPL;
330 static HRESULT WINAPI band_track_Clone(IDirectMusicTrack8 *iface, MUSIC_TIME mtStart,
331 MUSIC_TIME mtEnd, IDirectMusicTrack **ppTrack)
333 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
334 FIXME("(%p, %ld, %ld, %p): stub\n", This, mtStart, mtEnd, ppTrack);
335 return S_OK;
338 static HRESULT WINAPI band_track_PlayEx(IDirectMusicTrack8 *iface, void *state_data,
339 REFERENCE_TIME rtStart, REFERENCE_TIME rtEnd, REFERENCE_TIME rtOffset, DWORD flags,
340 IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state,
341 DWORD virtual_id)
343 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
345 FIXME("(%p, %p, 0x%s, 0x%s, 0x%s, %lx, %p, %p, %ld): stub\n", This, state_data, wine_dbgstr_longlong(rtStart),
346 wine_dbgstr_longlong(rtEnd), wine_dbgstr_longlong(rtOffset), flags, performance, segment_state, virtual_id);
348 return S_OK;
351 static HRESULT WINAPI band_track_GetParamEx(IDirectMusicTrack8 *iface,
352 REFGUID rguidType, REFERENCE_TIME rtTime, REFERENCE_TIME *rtNext, void *param,
353 void *state_data, DWORD flags)
355 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
357 FIXME("(%p, %s, 0x%s, %p, %p, %p, %lx): stub\n", This, debugstr_dmguid(rguidType),
358 wine_dbgstr_longlong(rtTime), rtNext, param, state_data, flags);
360 return S_OK;
363 static HRESULT WINAPI band_track_SetParamEx(IDirectMusicTrack8 *iface, REFGUID rguidType,
364 REFERENCE_TIME rtTime, void *param, void *state_data, DWORD flags)
366 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
368 FIXME("(%p, %s, 0x%s, %p, %p, %lx): stub\n", This, debugstr_dmguid(rguidType),
369 wine_dbgstr_longlong(rtTime), param, state_data, flags);
371 return S_OK;
374 static HRESULT WINAPI band_track_Compose(IDirectMusicTrack8 *iface, IUnknown *context,
375 DWORD trackgroup, IDirectMusicTrack **track)
377 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
379 TRACE("(%p, %p, %ld, %p): method not implemented\n", This, context, trackgroup, track);
380 return E_NOTIMPL;
383 static HRESULT WINAPI band_track_Join(IDirectMusicTrack8 *iface, IDirectMusicTrack *pNewTrack,
384 MUSIC_TIME mtJoin, IUnknown *pContext, DWORD dwTrackGroup,
385 IDirectMusicTrack **ppResultTrack)
387 struct band_track *This = impl_from_IDirectMusicTrack8(iface);
388 FIXME("(%p, %p, %ld, %p, %ld, %p): stub\n", This, pNewTrack, mtJoin, pContext, dwTrackGroup, ppResultTrack);
389 return S_OK;
392 static const IDirectMusicTrack8Vtbl band_track_vtbl =
394 band_track_QueryInterface,
395 band_track_AddRef,
396 band_track_Release,
397 band_track_Init,
398 band_track_InitPlay,
399 band_track_EndPlay,
400 band_track_Play,
401 band_track_GetParam,
402 band_track_SetParam,
403 band_track_IsParamSupported,
404 band_track_AddNotificationType,
405 band_track_RemoveNotificationType,
406 band_track_Clone,
407 band_track_PlayEx,
408 band_track_GetParamEx,
409 band_track_SetParamEx,
410 band_track_Compose,
411 band_track_Join,
414 static HRESULT parse_lbnd_list(struct band_track *This, IStream *stream, struct chunk_entry *parent)
416 struct chunk_entry chunk = {.parent = parent};
417 DMUS_IO_BAND_ITEM_HEADER2 header2;
418 struct band_entry *entry;
419 IDirectMusicBand *band;
420 HRESULT hr;
422 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
424 switch (MAKE_IDTYPE(chunk.id, chunk.type))
426 case DMUS_FOURCC_BANDITEM_CHUNK:
428 DMUS_IO_BAND_ITEM_HEADER header;
430 if (SUCCEEDED(hr = stream_chunk_get_data(stream, &chunk, &header, sizeof(header))))
432 header2.lBandTimeLogical = header.lBandTime;
433 header2.lBandTimePhysical = header.lBandTime;
436 break;
439 case DMUS_FOURCC_BANDITEM_CHUNK2:
440 hr = stream_chunk_get_data(stream, &chunk, &header2, sizeof(header2));
441 break;
443 case MAKE_IDTYPE(FOURCC_RIFF, DMUS_FOURCC_BAND_FORM):
445 IPersistStream *persist;
447 if (FAILED(hr = CoCreateInstance(&CLSID_DirectMusicBand, NULL, CLSCTX_INPROC_SERVER,
448 &IID_IDirectMusicBand, (void **)&band)))
449 break;
451 if (SUCCEEDED(hr = IDirectMusicBand_QueryInterface(band, &IID_IPersistStream, (void **)&persist)))
453 if (SUCCEEDED(hr = stream_reset_chunk_start(stream, &chunk)))
454 hr = IPersistStream_Load(persist, stream);
455 IPersistStream_Release(persist);
458 break;
461 default:
462 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
463 break;
466 if (FAILED(hr)) break;
469 if (FAILED(hr)) return hr;
471 if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY;
472 entry->head = header2;
473 entry->band = band;
474 IDirectMusicBand_AddRef(band);
475 list_add_tail(&This->bands, &entry->entry);
477 return S_OK;
480 static HRESULT parse_lbdl_list(struct band_track *This, IStream *stream, struct chunk_entry *parent)
482 struct chunk_entry chunk = {.parent = parent};
483 HRESULT hr;
485 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
487 switch (MAKE_IDTYPE(chunk.id, chunk.type))
489 case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_BAND_LIST):
490 hr = parse_lbnd_list(This, stream, &chunk);
491 break;
493 default:
494 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
495 break;
498 if (FAILED(hr)) break;
501 return S_OK;
504 static HRESULT parse_dmbt_chunk(struct band_track *This, IStream *stream, struct chunk_entry *parent)
506 struct chunk_entry chunk = {.parent = parent};
507 HRESULT hr;
509 if (FAILED(hr = dmobj_parsedescriptor(stream, parent, &This->dmobj.desc,
510 DMUS_OBJ_OBJECT|DMUS_OBJ_NAME|DMUS_OBJ_NAME_INAM|DMUS_OBJ_VERSION))
511 || FAILED(hr = stream_reset_chunk_data(stream, parent)))
512 return hr;
514 while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
516 switch (MAKE_IDTYPE(chunk.id, chunk.type))
518 case DMUS_FOURCC_GUID_CHUNK:
519 case DMUS_FOURCC_VERSION_CHUNK:
520 case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_UNFO_LIST):
521 /* already parsed by dmobj_parsedescriptor */
522 break;
524 case DMUS_FOURCC_BANDTRACK_CHUNK:
525 hr = stream_chunk_get_data(stream, &chunk, &This->header, sizeof(This->header));
526 break;
528 case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_BANDS_LIST):
529 hr = parse_lbdl_list(This, stream, &chunk);
530 break;
532 default:
533 FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
534 break;
537 if (FAILED(hr)) break;
540 return hr;
543 static inline struct band_track *impl_from_IPersistStream(IPersistStream *iface)
545 return CONTAINING_RECORD(iface, struct band_track, dmobj.IPersistStream_iface);
548 static HRESULT WINAPI band_track_persist_stream_Load(IPersistStream *iface, IStream *stream)
550 struct band_track *This = impl_from_IPersistStream(iface);
551 struct chunk_entry chunk = {0};
552 HRESULT hr;
554 TRACE("(%p, %p)\n", This, stream);
556 if ((hr = stream_get_chunk(stream, &chunk)) == S_OK)
558 switch (MAKE_IDTYPE(chunk.id, chunk.type))
560 case MAKE_IDTYPE(FOURCC_RIFF, DMUS_FOURCC_BANDTRACK_FORM):
561 hr = parse_dmbt_chunk(This, stream, &chunk);
562 break;
564 default:
565 WARN("Invalid band track chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type));
566 hr = DMUS_E_UNSUPPORTED_STREAM;
567 break;
571 stream_skip_chunk(stream, &chunk);
572 if (FAILED(hr)) return hr;
574 if (TRACE_ON(dmband))
576 struct band_entry *entry;
577 int i = 0;
579 TRACE("Loaded DirectMusicBandTrack %p\n", This);
580 dump_DMUS_OBJECTDESC(&This->dmobj.desc);
582 TRACE(" - header:\n");
583 TRACE(" - bAutoDownload: %u\n", This->header.bAutoDownload);
585 TRACE(" - bands:\n");
586 LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry)
588 TRACE(" - band[%u]: %p\n", i++, entry->band);
589 TRACE(" - lBandTimeLogical: %ld\n", entry->head.lBandTimeLogical);
590 TRACE(" - lBandTimePhysical: %ld\n", entry->head.lBandTimePhysical);
594 return S_OK;
597 static const IPersistStreamVtbl band_track_persist_stream_vtbl =
599 dmobj_IPersistStream_QueryInterface,
600 dmobj_IPersistStream_AddRef,
601 dmobj_IPersistStream_Release,
602 dmobj_IPersistStream_GetClassID,
603 unimpl_IPersistStream_IsDirty,
604 band_track_persist_stream_Load,
605 unimpl_IPersistStream_Save,
606 unimpl_IPersistStream_GetSizeMax,
609 /* for ClassFactory */
610 HRESULT create_dmbandtrack(REFIID lpcGUID, void **ppobj)
612 struct band_track *track;
613 HRESULT hr;
615 *ppobj = NULL;
616 if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY;
617 track->IDirectMusicTrack8_iface.lpVtbl = &band_track_vtbl;
618 track->ref = 1;
619 dmobject_init(&track->dmobj, &CLSID_DirectMusicBandTrack, (IUnknown *)&track->IDirectMusicTrack8_iface);
620 track->dmobj.IPersistStream_iface.lpVtbl = &band_track_persist_stream_vtbl;
621 list_init(&track->bands);
623 hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj);
624 IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface);
626 return hr;