1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS BDA Proxy
4  * FILE:            dll/directx/bdaplgin/devicecontrol.cpp
5  * PURPOSE:         ClassFactory interface
6  *
7  * PROGRAMMERS:     Johannes Anderwald (johannes.anderwald@reactos.org)
8  */
9 
10 #include "precomp.h"
11 
12 const GUID IID_IKsObject           = {0x423c13a2, 0x2070, 0x11d0, {0x9e, 0xf7, 0x00, 0xaa, 0x00, 0xa2, 0x16, 0xa1}};
13 
14 #ifndef _MSC_VER
15 const GUID CLSID_DVBTNetworkProvider = {0x216c62df, 0x6d7f, 0x4e9a, {0x85, 0x71, 0x5, 0xf1, 0x4e, 0xdb, 0x76, 0x6a}};
16 
17 const GUID KSPROPSETID_BdaTopology = {0xa14ee835, 0x0a23, 0x11d3, {0x9c, 0xc7, 0x0, 0xc0, 0x4f, 0x79, 0x71, 0xe0}};
18 const GUID KSMETHODSETID_BdaDeviceConfiguration = {0x71985f45, 0x1ca1, 0x11d3, {0x9c, 0xc8, 0x0, 0xc0, 0x4f, 0x79, 0x71, 0xe0}};
19 const GUID KSMETHODSETID_BdaChangeSync = {0xfd0a5af3, 0xb41d, 0x11d2, {0x9c, 0x95, 0x0, 0xc0, 0x4f, 0x79, 0x71, 0xe0}};
20 const GUID IID_IBaseFilter         = {0x56a86895, 0x0ad4, 0x11ce, {0xb0,0x3a, 0x00,0x20,0xaf,0x0b,0xa7,0x70}};
21 const GUID IID_IAsyncReader       = {0x56A868AA, 0x0AD4, 0x11CE, {0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70}};
22 const GUID IID_IAMOpenProgress    = {0x8E1C39A1, 0xDE53, 0x11cf, {0xAA, 0x63, 0x00, 0x80, 0xC7, 0x44, 0x52, 0x8D}};
23 const GUID IID_IBDA_Topology      = {0x79B56888, 0x7FEA, 0x4690, {0xB4, 0x5D, 0x38, 0xFD, 0x3C, 0x78, 0x49, 0xBE}};
24 const GUID IID_IBDA_NetworkProvider   = {0xfd501041, 0x8ebe, 0x11ce, {0x81, 0x83, 0x00, 0xaa, 0x00, 0x57, 0x7d, 0xa2}};
25 const GUID IID_IBDA_DeviceControl = {0xFD0A5AF3, 0xB41D, 0x11d2, {0x9C, 0x95, 0x00, 0xC0, 0x4F, 0x79, 0x71, 0xE0}};
26 
27 const GUID IID_IDistributorNotify = {0x56a868af, 0x0ad4, 0x11ce, {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
28 
29 #endif
30 
31 class CBDADeviceControl : public IBDA_DeviceControl,
32                           public IBDA_Topology
33 {
34 public:
35     STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
36 
37     STDMETHODIMP_(ULONG) AddRef()
38     {
39         InterlockedIncrement(&m_Ref);
40         return m_Ref;
41     }
42     STDMETHODIMP_(ULONG) Release()
43     {
44         InterlockedDecrement(&m_Ref);
45         if (!m_Ref)
46         {
47             delete this;
48             return 0;
49         }
50         return m_Ref;
51     }
52 
53     // IBDA_DeviceControl methods
54     HRESULT STDMETHODCALLTYPE StartChanges( void);
55     HRESULT STDMETHODCALLTYPE CheckChanges( void);
56     HRESULT STDMETHODCALLTYPE CommitChanges( void);
57     HRESULT STDMETHODCALLTYPE GetChangeState(ULONG *pState);
58 
59     // IBDA_Topology methods
60     HRESULT STDMETHODCALLTYPE GetNodeTypes(ULONG *pulcNodeTypes, ULONG ulcNodeTypesMax, ULONG * rgulNodeTypes);
61     HRESULT STDMETHODCALLTYPE GetNodeDescriptors(ULONG *ulcNodeDescriptors, ULONG ulcNodeDescriptorsMax, BDANODE_DESCRIPTOR * rgNodeDescriptors);
62     HRESULT STDMETHODCALLTYPE GetNodeInterfaces(ULONG ulNodeType, ULONG *pulcInterfaces, ULONG ulcInterfacesMax, GUID * rgguidInterfaces);
63     HRESULT STDMETHODCALLTYPE GetPinTypes(ULONG *pulcPinTypes, ULONG ulcPinTypesMax, ULONG *rgulPinTypes);
64     HRESULT STDMETHODCALLTYPE GetTemplateConnections(ULONG *pulcConnections, ULONG ulcConnectionsMax, BDA_TEMPLATE_CONNECTION * rgConnections);
65     HRESULT STDMETHODCALLTYPE CreatePin(ULONG ulPinType, ULONG *pulPinId);
66     HRESULT STDMETHODCALLTYPE DeletePin(ULONG ulPinId);
67     HRESULT STDMETHODCALLTYPE SetMediaType(ULONG ulPinId, AM_MEDIA_TYPE *pMediaType);
68     HRESULT STDMETHODCALLTYPE SetMedium(ULONG ulPinId, REGPINMEDIUM *pMedium);
69     HRESULT STDMETHODCALLTYPE CreateTopology(ULONG ulInputPinId, ULONG ulOutputPinId);
70     HRESULT STDMETHODCALLTYPE GetControlNode(ULONG ulInputPinId, ULONG ulOutputPinId, ULONG ulNodeType, IUnknown **ppControlNode);
71 
72     CBDADeviceControl(IUnknown * pUnkOuter, IBaseFilter *pFilter, HANDLE hFile) : m_Ref(0), m_pUnkOuter(pUnkOuter), m_Handle(hFile), m_pFilter(pFilter){};
73     virtual ~CBDADeviceControl(){};
74 
75 protected:
76     LONG m_Ref;
77     IUnknown * m_pUnkOuter;
78     HANDLE m_Handle;
79     IBaseFilter * m_pFilter;
80 };
81 
82 HRESULT
83 STDMETHODCALLTYPE
84 CBDADeviceControl::QueryInterface(
85     IN  REFIID refiid,
86     OUT PVOID* Output)
87 {
88     *Output = NULL;
89 
90     if (IsEqualGUID(refiid, IID_IUnknown))
91     {
92         *Output = PVOID(this);
93         reinterpret_cast<IUnknown*>(*Output)->AddRef();
94         return NOERROR;
95     }
96     if (IsEqualGUID(refiid, IID_IBDA_DeviceControl))
97     {
98         *Output = (IBDA_DeviceControl*)(this);
99         reinterpret_cast<IBDA_DeviceControl*>(*Output)->AddRef();
100         return NOERROR;
101     }
102 
103     if (IsEqualGUID(refiid, IID_IBDA_Topology))
104     {
105         *Output = (IBDA_Topology*)(this);
106         reinterpret_cast<IBDA_Topology*>(*Output)->AddRef();
107         return NOERROR;
108     }
109 
110     return E_NOINTERFACE;
111 }
112 
113 
114 //-------------------------------------------------------------------
115 // IBDA_DeviceControl methods
116 //
117 HRESULT
118 STDMETHODCALLTYPE
119 CBDADeviceControl::StartChanges( void)
120 {
121     KSMETHOD Method;
122     HRESULT hr;
123     ULONG BytesReturned;
124 
125     /* setup request */
126     Method.Set = KSMETHODSETID_BdaChangeSync;
127     Method.Id = KSMETHOD_BDA_START_CHANGES;
128     Method.Flags = KSMETHOD_TYPE_NONE;
129 
130     /* execute request */
131     hr = KsSynchronousDeviceControl(m_Handle, IOCTL_KS_METHOD, (PVOID)&Method, sizeof(KSMETHOD), NULL, 0, &BytesReturned);
132 
133 #ifdef BDAPLGIN_TRACE
134     WCHAR Buffer[100];
135     swprintf(Buffer, L"CBDADeviceControl::StartChanges: hr %lx, BytesReturned %lu\n", hr, BytesReturned);
136     OutputDebugStringW(Buffer);
137 #endif
138 
139     return hr;
140 }
141 
142 
143 HRESULT
144 STDMETHODCALLTYPE
145 CBDADeviceControl::CheckChanges( void)
146 {
147     KSMETHOD Method;
148     HRESULT hr;
149     ULONG BytesReturned;
150 
151     /* setup request */
152     Method.Set = KSMETHODSETID_BdaChangeSync;
153     Method.Id = KSMETHOD_BDA_CHECK_CHANGES;
154     Method.Flags = KSMETHOD_TYPE_NONE;
155 
156     /* execute request */
157     hr = KsSynchronousDeviceControl(m_Handle, IOCTL_KS_METHOD, (PVOID)&Method, sizeof(KSMETHOD), NULL, 0, &BytesReturned);
158 
159 #ifdef BDAPLGIN_TRACE
160     WCHAR Buffer[100];
161     swprintf(Buffer, L"CBDADeviceControl::CheckChanges: hr %lx, BytesReturned %lu\n", hr, BytesReturned);
162     OutputDebugStringW(Buffer);
163 #endif
164 
165     return hr;
166 }
167 
168 
169 HRESULT
170 STDMETHODCALLTYPE
171 CBDADeviceControl::CommitChanges( void)
172 {
173     KSMETHOD Method;
174     HRESULT hr;
175     ULONG BytesReturned;
176 
177     /* setup request */
178     Method.Set = KSMETHODSETID_BdaChangeSync;
179     Method.Id = KSMETHOD_BDA_COMMIT_CHANGES;
180     Method.Flags = KSMETHOD_TYPE_NONE;
181 
182     /* execute request */
183     hr = KsSynchronousDeviceControl(m_Handle, IOCTL_KS_METHOD, (PVOID)&Method, sizeof(KSMETHOD), NULL, 0, &BytesReturned);
184 
185 #ifdef BDAPLGIN_TRACE
186     WCHAR Buffer[100];
187     swprintf(Buffer, L"CBDADeviceControl::CommitChanges: hr %lx, BytesReturned %lu\n", hr, BytesReturned);
188     OutputDebugStringW(Buffer);
189 #endif
190 
191     return hr;
192 }
193 
194 HRESULT
195 STDMETHODCALLTYPE
196 CBDADeviceControl::GetChangeState(ULONG *pState)
197 {
198     if (pState)
199     {
200         *pState = BDA_CHANGES_COMPLETE;
201         return S_OK;
202     }
203     else
204     {
205         return E_POINTER;
206     }
207 }
208 
209 //-------------------------------------------------------------------
210 // IBDA_Topology methods
211 //
212 HRESULT
213 STDMETHODCALLTYPE
214 CBDADeviceControl::GetNodeTypes(ULONG *pulcNodeTypes, ULONG ulcNodeTypesMax, ULONG * rgulNodeTypes)
215 {
216     KSPROPERTY Property;
217     HRESULT hr;
218     ULONG BytesReturned;
219 
220     // setup request
221     Property.Set = KSPROPSETID_BdaTopology;
222     Property.Id = KSPROPERTY_BDA_NODE_TYPES;
223     Property.Flags = KSPROPERTY_TYPE_GET;
224 
225     // perform request
226     hr = KsSynchronousDeviceControl(m_Handle, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), rgulNodeTypes, sizeof(ULONG) * ulcNodeTypesMax, &BytesReturned);
227 
228     *pulcNodeTypes = (BytesReturned / sizeof(ULONG));
229 
230 #ifdef BDAPLGIN_TRACE
231     WCHAR Buffer[100];
232     swprintf(Buffer, L"CBDADeviceControl::GetNodeTypes: hr %lx, BytesReturned %lu\n", hr, BytesReturned);
233     OutputDebugStringW(Buffer);
234 
235     if (SUCCEEDED(hr))
236     {
237         for(ULONG Index = 0; Index < *pulcNodeTypes; Index++)
238         {
239             swprintf(Buffer, L"CBDADeviceControl::GetPinTypes: Index %lu Value %lx\n", Index, rgulNodeTypes[Index]);
240             OutputDebugStringW(Buffer);
241         }
242     }
243 #endif
244 
245     return hr;
246 }
247 
248 HRESULT
249 STDMETHODCALLTYPE
250 CBDADeviceControl::GetNodeDescriptors(ULONG *ulcNodeDescriptors, ULONG ulcNodeDescriptorsMax, BDANODE_DESCRIPTOR * rgNodeDescriptors)
251 {
252     KSPROPERTY Property;
253     HRESULT hr;
254     ULONG BytesReturned;
255 
256 
257     // setup request
258     Property.Set = KSPROPSETID_BdaTopology;
259     Property.Id = KSPROPERTY_BDA_NODE_DESCRIPTORS;
260     Property.Flags = KSPROPERTY_TYPE_GET;
261 
262     // perform request
263     hr = KsSynchronousDeviceControl(m_Handle, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), rgNodeDescriptors, sizeof(BDANODE_DESCRIPTOR) * ulcNodeDescriptorsMax, &BytesReturned);
264 
265     *ulcNodeDescriptors = (BytesReturned / sizeof(BDANODE_DESCRIPTOR));
266 
267 #ifdef BDAPLGIN_TRACE
268     WCHAR Buffer[1000];
269     swprintf(Buffer, L"CBDADeviceControl::GetNodeDescriptors: hr %lx, BytesReturned %lu\n", hr, BytesReturned);
270     OutputDebugStringW(Buffer);
271 
272 
273     if (SUCCEEDED(hr))
274     {
275         for(ULONG Index = 0; Index < min(*ulcNodeDescriptors, ulcNodeDescriptorsMax); Index++)
276         {
277             LPOLESTR pGUIDFunction, pGUIDName;
278 
279             StringFromCLSID(rgNodeDescriptors[Index].guidFunction, &pGUIDFunction);
280             StringFromCLSID(rgNodeDescriptors[Index].guidName, &pGUIDName);
281 
282             swprintf(Buffer, L"CBDADeviceControl::GetPinTypes: Index %lu Value %lx\nFunction %s\n Name %s\n-----\n", Index, rgNodeDescriptors[Index].ulBdaNodeType, pGUIDFunction, pGUIDName);
283             OutputDebugStringW(Buffer);
284         }
285     }
286 #endif
287 
288 
289     return hr;
290 }
291 
292 HRESULT
293 STDMETHODCALLTYPE
294 CBDADeviceControl::GetNodeInterfaces(ULONG ulNodeType, ULONG *pulcInterfaces, ULONG ulcInterfacesMax, GUID * rgguidInterfaces)
295 {
296     KSP_NODE Property;
297     HRESULT hr;
298     ULONG BytesReturned;
299 
300 
301     // setup request
302     Property.Property.Set = KSPROPSETID_BdaTopology;
303     Property.Property.Id = KSPROPERTY_BDA_NODE_PROPERTIES;
304     Property.Property.Flags = KSPROPERTY_TYPE_GET;
305     Property.NodeId = ulNodeType;
306     Property.Reserved = 0;
307 
308     // perform request
309     hr = KsSynchronousDeviceControl(m_Handle, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_NODE), rgguidInterfaces, sizeof(GUID) * ulcInterfacesMax, &BytesReturned);
310 
311     *pulcInterfaces = (BytesReturned / sizeof(GUID));
312 
313 #ifdef BDAPLGIN_TRACE
314     WCHAR Buffer[100];
315     swprintf(Buffer, L"CBDADeviceControl::GetNodeInterfaces: hr %lx, BytesReturned %lu ulNodeType %lu\n", hr, BytesReturned, ulNodeType);
316     OutputDebugStringW(Buffer);
317 
318     if (SUCCEEDED(hr))
319     {
320         for(ULONG Index = 0; Index < min(*pulcInterfaces, ulcInterfacesMax); Index++)
321         {
322             LPOLESTR pstr;
323 
324             StringFromCLSID(rgguidInterfaces[Index], &pstr);
325 
326             swprintf(Buffer, L"CBDADeviceControl::GetNodeInterfaces: Index %lu Name %s\n", Index, pstr);
327             OutputDebugStringW(Buffer);
328         }
329     }
330 #endif
331 
332     return hr;
333 }
334 
335 HRESULT
336 STDMETHODCALLTYPE
337 CBDADeviceControl::GetPinTypes(ULONG *pulcPinTypes, ULONG ulcPinTypesMax, ULONG *rgulPinTypes)
338 {
339     KSPROPERTY Property;
340     HRESULT hr;
341     ULONG BytesReturned;
342 
343     // setup request
344     Property.Set = KSPROPSETID_BdaTopology;
345     Property.Id = KSPROPERTY_BDA_PIN_TYPES;
346     Property.Flags = KSPROPERTY_TYPE_GET;
347 
348     // perform request
349     hr = KsSynchronousDeviceControl(m_Handle, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), rgulPinTypes, sizeof(ULONG) * ulcPinTypesMax, &BytesReturned);
350 
351     *pulcPinTypes = (BytesReturned / sizeof(ULONG));
352 
353 #ifdef BDAPLGIN_TRACE
354     WCHAR Buffer[100];
355     swprintf(Buffer, L"CBDADeviceControl::GetPinTypes: hr %lx, BytesReturned %lu\n", hr, BytesReturned);
356     OutputDebugStringW(Buffer);
357 
358     if (SUCCEEDED(hr))
359     {
360         for(ULONG Index = 0; Index < *pulcPinTypes; Index++)
361         {
362             swprintf(Buffer, L"CBDADeviceControl::GetPinTypes: Index %lu Value %lx\n", Index, rgulPinTypes[Index]);
363             OutputDebugStringW(Buffer);
364         }
365     }
366 #endif
367 
368     return hr;
369 }
370 
371 HRESULT
372 STDMETHODCALLTYPE
373 CBDADeviceControl::GetTemplateConnections(ULONG *pulcConnections, ULONG ulcConnectionsMax, BDA_TEMPLATE_CONNECTION * rgConnections)
374 {
375 #ifdef BDAPLGIN_TRACE
376     OutputDebugStringW(L"CBDADeviceControl::GetTemplateConnections: NotImplemented\n");
377 #endif
378 
379     return E_NOTIMPL;
380 }
381 
382 HRESULT
383 STDMETHODCALLTYPE
384 CBDADeviceControl::CreatePin(ULONG ulPinType, ULONG *pulPinId)
385 {
386 #ifdef BDAPLGIN_TRACE
387     OutputDebugStringW(L"CBDADeviceControl::CreatePin: NotImplemented\n");
388 #endif
389 
390     return E_NOTIMPL;
391 }
392 
393 HRESULT
394 STDMETHODCALLTYPE
395 CBDADeviceControl::DeletePin(ULONG ulPinId)
396 {
397 #ifdef BDAPLGIN_TRACE
398     OutputDebugStringW(L"CBDADeviceControl::DeletePin: NotImplemented\n");
399 #endif
400 
401     return E_NOTIMPL;
402 }
403 
404 HRESULT
405 STDMETHODCALLTYPE
406 CBDADeviceControl::SetMediaType(ULONG ulPinId, AM_MEDIA_TYPE *pMediaType)
407 {
408 #ifdef BDAPLGIN_TRACE
409     OutputDebugStringW(L"CBDADeviceControl::SetMediaType: NotImplemented\n");
410 #endif
411 
412     return E_NOTIMPL;
413 }
414 
415 HRESULT
416 STDMETHODCALLTYPE
417 CBDADeviceControl::SetMedium(ULONG ulPinId, REGPINMEDIUM *pMedium)
418 {
419 #ifdef BDAPLGIN_TRACE
420     OutputDebugStringW(L"CBDADeviceControl::SetMedium: NotImplemented\n");
421 #endif
422 
423     return E_NOTIMPL;
424 }
425 
426 HRESULT
427 STDMETHODCALLTYPE
428 CBDADeviceControl::CreateTopology(ULONG ulInputPinId, ULONG ulOutputPinId)
429 {
430     KSM_BDA_PIN_PAIR Method;
431     HRESULT hr;
432     ULONG BytesReturned = 0;
433 
434     Method.Method.Flags  = KSMETHOD_TYPE_NONE;
435     Method.Method.Id = KSMETHOD_BDA_CREATE_TOPOLOGY;
436     Method.Method.Set = KSMETHODSETID_BdaDeviceConfiguration;
437     Method.InputPinId = ulInputPinId;
438     Method.OutputPinId = ulOutputPinId;
439 
440     hr = KsSynchronousDeviceControl(m_Handle, IOCTL_KS_METHOD, (PVOID)&Method, sizeof(KSM_BDA_PIN_PAIR), NULL, 0, &BytesReturned);
441 
442 #ifdef BDAPLGIN_TRACE
443     WCHAR Buffer[100];
444     swprintf(Buffer, L"CBDADeviceControl::CreateTopology: hr %lx, BytesReturned %lu\n", hr, BytesReturned);
445     OutputDebugStringW(Buffer);
446 #endif
447 
448     return hr;
449 }
450 
451 HRESULT
452 STDMETHODCALLTYPE
453 CBDADeviceControl::GetControlNode(ULONG ulInputPinId, ULONG ulOutputPinId, ULONG ulNodeType, IUnknown **ppControlNode)
454 {
455     HRESULT hr;
456     ULONG PinId = 0;
457     ULONG BytesReturned;
458     KSP_BDA_NODE_PIN Property;
459 
460     //setup request
461     Property.Property.Set = KSPROPSETID_BdaTopology;
462     Property.Property.Id = KSPROPERTY_BDA_CONTROLLING_PIN_ID;
463     Property.Property.Flags = KSPROPERTY_TYPE_GET;
464     Property.ulInputPinId = ulInputPinId;
465     Property.ulOutputPinId = ulOutputPinId;
466     Property.ulNodeType = ulNodeType;
467 
468     // perform request
469     // WinXP SP3 expects minimum sizeof(KSP_BDA_NODE_PIN) + sizeof(ULONG)
470     // seems a driver to be a driver bug
471 
472     hr = KsSynchronousDeviceControl(m_Handle, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_BDA_NODE_PIN) + sizeof(ULONG), &PinId, sizeof(ULONG), &BytesReturned);
473 
474 #ifdef BDAPLGIN_TRACE
475     WCHAR Buffer[200];
476     swprintf(Buffer, L"CBDADeviceControl::GetControlNode: hr %lx, BytesReturned %lu PinId %lu ulInputPinId %lu ulOutputPinId %lu ulNodeType %lu\n", hr, BytesReturned, PinId, ulInputPinId, ulOutputPinId, ulNodeType);
477     OutputDebugStringW(Buffer);
478 #endif
479 
480     if (FAILED(hr))
481         return hr;
482 
483     hr = CControlNode_fnConstructor(m_pFilter, ulNodeType, PinId, IID_IUnknown, (LPVOID*)ppControlNode);
484 
485 #ifdef BDAPLGIN_TRACE
486     swprintf(Buffer, L"CBDADeviceControl::GetControlNode: hr %lx\n", hr);
487     OutputDebugStringW(Buffer);
488 #endif
489 
490     return hr;
491 }
492 
493 HRESULT
494 WINAPI
495 CBDADeviceControl_fnConstructor(
496     IUnknown * pUnkOuter,
497     REFIID riid,
498     LPVOID * ppv)
499 {
500     HRESULT hr;
501     IKsObject *pObject = NULL;
502     IBaseFilter *pFilter = NULL;
503     HANDLE hFile;
504 
505 #ifdef BDAPLGIN_TRACE
506     OutputDebugStringW(L"CBDADeviceControl_fnConstructor\n");
507 #endif
508 
509     //DebugBreak();
510 
511     // sanity check
512     assert(pUnkOuter);
513 
514     // query for IKsObject
515     hr = pUnkOuter->QueryInterface(IID_IKsObject, (void**)&pObject);
516 
517     if (FAILED(hr))
518         return E_NOINTERFACE;
519 
520     // sanity check
521     assert(hr == NOERROR);
522 
523     // query for IBaseFilter interface support
524     hr = pUnkOuter->QueryInterface(IID_IBaseFilter, (void**)&pFilter);
525 
526     if (FAILED(hr))
527     {
528         // release
529        pObject->Release();
530        return E_NOINTERFACE;
531     }
532 
533     // another sanity check
534     assert(pObject != NULL);
535 
536     // get file handle
537     hFile = pObject->KsGetObjectHandle();
538 
539     // one more sanity check
540     assert(hFile != NULL && hFile != INVALID_HANDLE_VALUE);
541 
542     // release IKsObject interface
543     pObject->Release();
544 
545     // release filter
546     pFilter->Release();
547 
548     // construct device control
549     CBDADeviceControl * handler = new CBDADeviceControl(pUnkOuter, pFilter, hFile);
550 
551     if (!handler)
552         return E_OUTOFMEMORY;
553 
554     if (FAILED(handler->QueryInterface(riid, ppv)))
555     {
556         /* not supported */
557         delete handler;
558         return E_NOINTERFACE;
559     }
560 
561     return NOERROR;
562 }
563