|
|
|
date: Mon, 15 Sep 2008 16:01:13 -0700 (PDT),
group: microsoft.public.win32.programmer.directx.video
back
Re: DMO manually created for graph with wrapper?
On Sep 16, 9:53 am, "Alessandro Angeli"
wrote:
> From: "Roman Ryl..."
>
> > I suppose it is quite OK to have a regular COM class
> > registered but not registered using DMORegister. And then
> > use this CLSID as an argument for
> > IDMOWrapperFilter::Init. If the project is ATL based it
> > is simple, just recently I used this scenario and it
> > worked well.
>
> Yes, it is OK. COM registration is required to use the
> DMOWrapper while DMO registration is only required for the
> SysDevEnum (which uses the DMOWrapper, so it implies COM
> registration as well).
>
> If you don't want any registraion at all and still want to
> use the DMOWrapper, you need to use CoRegisterClassObject()
> or hook the registry APIs.
>
> --
> // Alessandro Angeli
> // MVP :: DirectShow / MediaFoundation
> // mvpnews at riseoftheants dot com
> //http://www.riseoftheants.com/mmx/faq.htm
Thank you for the quick response on this. After reviewing the
solution and docs, I realize that I did not clearly state the layout
of my implementation for which I appologize.
We have a custom encoder and decoder for which we wrote DMOs for. We
did so for the decoder so that it would run under WMP. On encoder
machines that we build and ship, we take precautions so that the
registered DMO cannot be used on a machine we didn't ship it on.
However, as we now have an application that will require the encoder
to be distributied widely, I needed to come up with at way to protect
it as well. In reviewing the wmvmux sample, I saw how to create and
use a dshow filter internally without having to register it so it
could not be used in others apps. Before my original post, I had
modifed my code where we build our graph to use the DMO so that I
incorporated the .h/.cpp files from our DMO solution as I wanted to be
able to use it without shipping our DMO itself. This would keep the
two projects pointing to same source. What I didn't include was the
Dll functions that are used by the DMO for registration, etc.
However, where I mislead in my description is that the creation of the
dshow graph is housed in a dll (this was not originally any type of
COM object but a dll with exported classes/functions) which is used by
an ocx with the actual "application" being IE. Although I'm not that
familar with the CoRegisterClassObject, the docs lead me to believe
that I can't call this from within a dll. Is this correct? I've
tried to implement this functionality as described in the dll that
constructs the graph but without success:
this is declared in a header file in the dll project:
CComPtr<IBaseFilter> pVideoCompressor2;
CComObject<CSILKEncoderDMO>* pMyEncoder;
within a function of the .cpp I have:
hr = pVideoCompressor2.CoCreateInstance( CLSID_DMOWrapperFilter );
if (FAILED(hr))
{
svcParent->LogEventEx(
1
, TEXT( "ERROR -
pVideoCompressor2.CoCreateInstance( CLSID_DMOWrapperFilter )" )
, EVENTLOG_ERROR_TYPE
);
return hr;
}
CComQIPtr<IDMOWrapperFilter> pWrapperFilter( pVideoCompressor2 );
pMyEncoder = NULL;
hr = CComObject<CSILKEncoderDMO>::CreateInstance( &pMyEncoder );
if (FAILED(hr))
{
svcParent->LogEventEx(
1
, TEXT( "ERROR -
CComObject<CSILKEncoderDMO>::CreateInstance( &pMyEncoder )" )
, EVENTLOG_ERROR_TYPE
);
return hr;
}
IUnknown* punk =
reinterpret_cast<IUnknown*>( pMyEncoder );
hr = CoRegisterClassObject(
CLSID_SILKEncoderDMO
, punk
, CLSCTX_INPROC_SERVER
, REGCLS_MULTI_SEPARATE
, &m_dwRegFlag
);
hr = pWrapperFilter->Init( CLSID_SILKEncoderDMO,
DMOCATEGORY_VIDEO_ENCODER );
Up to the point of pWrapperFilter->Init, all hr return 0x00 and
m_dwRegFlag has a value. However, when pWrapperFilter->Init is
called, it returns a 0x80004002 (Interface not supported error.).
The class for the dmo is declared as:
class ATL_NO_VTABLE CSILKEncoderDMO :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CSILKEncoderDMO, &CLSID_SILKEncoderDMO>,
public IDispatchImpl<ISILKEncoderDMO, &IID_ISILKEncoderDMO,
&LIBID_dmoSILKEncLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
public IMediaObjectImpl<CSILKEncoderDMO, 1, 1>
I've tried setting breakpoints in the dmo code and can see it being
created, however, I'm not sure what interface it is failing on.
Am I not implementing the described solution correctly? Originally I
had thought that I would need to create a dshow filter to get this to
work but I would like not to if possible.
Thank you for all of the help!
Mike
date: Tue, 16 Sep 2008 13:02:17 -0700 (PDT)
author: mike
Re: DMO manually created for graph with wrapper?
From: "mike"
[...]
> Am I not implementing the described solution correctly?
No, you're not.
Here is a primer on how CoCreateInstance() (which is what
IDMOWrapperFilter::Init() uses) works for
CLSCTX_INPROC_SERVER:
1. it looks up an IClassFactory object associated to the
CLSID
2. if there is none, it loads the DLL server specified in
[HKCR\CLSID\<clsid>\InprocServer32]@ and calls its
DllGetClassObject() to retrieve an IClassFactory
3. once it has an IClassFactory object, it call
IClassFactory::CreateInstance() to create an instance of the
requested object
So you actually have to supply 2 COM objects for the given
CLSID: the class factory, which is used to create instances
of the actual object, and the actual object. The class
factory and the DllGetClassObject() export are usually
provided by the framework behind your back, so you don't
even notice.
In this case, since you don't want to package the DMO in a
DLL server and register it, you must use
CoRegisterClassObject() at runtime so that
CoCreateInstance() succeeds at step 1.
In you code, you passed an instance of the actual object to
CoRegisterClassObject() instead of an instance of the class
factory, hence the failure.
Frankly, I have no idea where ATL hides the class factory it
generates for you but here are a couple of ides:
- let ATL produce the DllGetClassObject() DLL export, but
remove it from the .def file, so that it is not really
exported then call it directly like you would call any other
internal function
- implement IClassFactory yourself since after all it is a
very stupid internal COM object (LockServer() can just
return S_OK or maybe even E_NOTIMPL and CreateInstance()
just returns an instance of the actual object)
--
// Alessandro Angeli
// MVP :: DirectShow / MediaFoundation
// mvpnews at riseoftheants dot com
// http://www.riseoftheants.com/mmx/faq.htm
date: Tue, 16 Sep 2008 17:11:25 -0400
author: Alessandro Angeli
Re: DMO manually created for graph with wrapper?
On Sep 16, 2:11 pm, "Alessandro Angeli"
wrote:
> From: "mike"
>
> [...]
>
> > Am I not implementing the described solution correctly?
>
> No, you're not.
>
> Here is a primer on how CoCreateInstance() (which is what
> IDMOWrapperFilter::Init() uses) works for
> CLSCTX_INPROC_SERVER:
>
> 1. it looks up an IClassFactory object associated to the
> CLSID
>
> 2. if there is none, it loads the DLL server specified in
> [HKCR\CLSID\<clsid>\InprocServer32]@ and calls its
> DllGetClassObject() to retrieve an IClassFactory
>
> 3. once it has an IClassFactory object, it call
> IClassFactory::CreateInstance() to create an instance of the
> requested object
>
> So you actually have to supply 2 COM objects for the given
> CLSID: the class factory, which is used to create instances
> of the actual object, and the actual object. The class
> factory and the DllGetClassObject() export are usually
> provided by the framework behind your back, so you don't
> even notice.
>
> In this case, since you don't want to package the DMO in a
> DLL server and register it, you must use
> CoRegisterClassObject() at runtime so that
> CoCreateInstance() succeeds at step 1.
>
> In you code, you passed an instance of the actual object to
> CoRegisterClassObject() instead of an instance of the class
> factory, hence the failure.
>
> Frankly, I have no idea where ATL hides the class factory it
> generates for you but here are a couple of ides:
>
> - let ATL produce the DllGetClassObject() DLL export, but
> remove it from the .def file, so that it is not really
> exported then call it directly like you would call any other
> internal function
>
> - implement IClassFactory yourself since after all it is a
> very stupid internal COM object (LockServer() can just
> return S_OK or maybe even E_NOTIMPL and CreateInstance()
> just returns an instance of the actual object)
>
> --
> // Alessandro Angeli
> // MVP :: DirectShow / MediaFoundation
> // mvpnews at riseoftheants dot com
> //http://www.riseoftheants.com/mmx/faq.htm
Alessandro,
Excellent - Thank you for the help and patience...
modifications:
derived from CComClassFactory...
class ATL_NO_VTABLE CSILKEncoderDMO :
public CComClassFactory, //CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CSILKEncoderDMO, &CLSID_SILKEncoderDMO>,
public IDispatchImpl<ISILKEncoderDMO, &IID_ISILKEncoderDMO,
&LIBID_dmoSILKEncLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
public IMediaObjectImpl<CSILKEncoderDMO, 1, 1>
changed calling code as follows:
IUnknown* punk = NULL;
//reinterpret_cast<IUnknown*>( pMyEncoder );
DllGetClassObject(
CLSID_SILKEncoderDMO
, IID_IClassFactory//IID_ISILKEncoderDMO
, ( PVOID* )&punk
);
hr = CoRegisterClassObject(
CLSID_SILKEncoderDMO
, punk
, CLSCTX_INPROC_SERVER
, REGCLS_MULTI_SEPARATE
, &m_dwRegFlag
);
date: Tue, 16 Sep 2008 15:23:57 -0700 (PDT)
author: mike
Re: DMO manually created for graph with wrapper?
Hi,
> > As you already have a regular COM class and it has its
> > OBJECT_ENTRY, CoRegisterClassObject is already done for
> > you by ATL base, you don't need to call this API
> > yourselves.
>
> I would be surprised if it did: when you build an inproc
> server, there is no need to call CoRegisterClassObject() at
> runtime, since standard inproc servers packaged in a DLL
> (which is I believe what ATL produces by default) use the
> registry entries and the DllGetClassObject() export to
> locate the class factory.
OK, you are correct here, but things are still very much simpler as
they seem.
Given a regular COM class:
===
#pragma once
#include "ClassFactorySample01_i.h"
class ATL_NO_VTABLE CFoo :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CFoo, &CLSID_Foo>,
public IFoo
{
public:
DECLARE_REGISTRY_RESOURCEID(IDR_FOO)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CFoo)
COM_INTERFACE_ENTRY(IFoo)
END_COM_MAP()
public:
// CFoo
CFoo()
{
ATLTRACE2(atlTraceRefcount, 4, _T("this 0x%08x\n"), this);
}
};
OBJECT_ENTRY_AUTO(__uuidof(Foo), CFoo)
extern "C" inline __declspec(dllexport) INT STDMETHODCALLTYPE Test()
{
ATLVERIFY(SUCCEEDED(CoInitialize(NULL)));
{
CComPtr<IFoo> pFoo;
HRESULT nResult = pFoo.CoCreateInstance(CLSID_Foo);
}
CoUninitialize();
return 0;
}
===
Class factory is already here available through inheritance from
CComCoClass. No need to bother creating new one. To disable
registration of the COM class through registry it is required to (one
of the ways) comment out DECLARE_REGISTRY_RESOURCEID and provide empty
UpdateRegistry method. Class factory is accessible through
OBJECT_ENTRY_AUTO's created __objMap_CFoo variable. Here it goes:
===
#pragma once
#include "ClassFactorySample01_i.h"
class ATL_NO_VTABLE CFoo :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CFoo, &CLSID_Foo>,
public IFoo
{
public:
//DECLARE_REGISTRY_RESOURCEID(IDR_FOO)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CFoo)
COM_INTERFACE_ENTRY(IFoo)
END_COM_MAP()
public:
// CFoo
static HRESULT STDMETHODCALLTYPE UpdateRegistry(BOOL)
{
return S_OK;
}
CFoo()
{
ATLTRACE2(atlTraceRefcount, 4, _T("this 0x%08x\n"), this);
}
};
OBJECT_ENTRY_AUTO(__uuidof(Foo), CFoo)
extern "C" inline __declspec(dllexport) INT STDMETHODCALLTYPE Test()
{
ATLVERIFY(SUCCEEDED(CoInitialize(NULL)));
{
ATLVERIFY(SUCCEEDED(__objMap_CFoo.RegisterClassObject(CLSCTX_INPROC_SERVER,
REGCLS_MULTI_SEPARATE)));
CComPtr<IFoo> pFoo;
HRESULT nResult = pFoo.CoCreateInstance(CLSID_Foo);
ATLVERIFY(SUCCEEDED(__objMap_CFoo.RevokeClassObject()));
}
CoUninitialize();
return 0;
}
===
And that's it. If the code was created by older versions of Visual
Studio with OBJECT_ENTRY instead of OBJECT_ENTRY_AUTO, the structure
pointed to by __objMap_CFoo needs to be looked up from OBJECT_MAP.
Roman
date: Tue, 16 Sep 2008 22:42:33 -0700 (PDT)
author: Roman Ryl...
Re: DMO manually created for graph with wrapper?
From: "mike"
> class ATL_NO_VTABLE CSILKEncoderDMO :
> public CComClassFactory,
The class factory and the actual object class should be 2
separate classes, not the same one! Granted that it may work
this way too if you really know what you are doing, but this
is not the right way in your case.
> IUnknown* punk = NULL;
> //reinterpret_cast<IUnknown*>( pMyEncoder );
>
> DllGetClassObject(
> CLSID_SILKEncoderDMO
> , IID_IClassFactory//IID_ISILKEncoderDMO
> , ( PVOID* )&punk
> );
punk should be of type IClassFactory*, not IUnknown*. Notice
that, since every COM interface inherits IUnknown, you pass
any interface wherever IUnknown is expected, without casts
or QueryInterface()s.
If you are using DllGetClassObject(), ATL will provide the
class factory for you and you do not need to implement it
yourself. Read Roman's latest post, who knows about ATL.
--
// Alessandro Angeli
// MVP :: DirectShow / MediaFoundation
// mvpnews at riseoftheants dot com
// http://www.riseoftheants.com/mmx/faq.htm
date: Wed, 17 Sep 2008 12:45:48 -0400
author: Alessandro Angeli
Re: DMO manually created for graph with wrapper?
On Sep 17, 9:45 am, "Alessandro Angeli"
wrote:
> From: "mike"
>
> > class ATL_NO_VTABLE CSILKEncoderDMO :
> > public CComClassFactory,
>
> The class factory and the actual object class should be 2
> separate classes, not the same one! Granted that it may work
> this way too if you really know what you are doing, but this
> is not the right way in your case.
>
> > IUnknown* punk = NULL;
> > //reinterpret_cast<IUnknown*>( pMyEncoder );
>
> > DllGetClassObject(
> > CLSID_SILKEncoderDMO
> > , IID_IClassFactory//IID_ISILKEncoderDMO
> > , ( PVOID* )&punk
> > );
>
> punk should be of type IClassFactory*, not IUnknown*. Notice
> that, since every COM interface inherits IUnknown, you pass
> any interface wherever IUnknown is expected, without casts
> or QueryInterface()s.
>
> If you are using DllGetClassObject(), ATL will provide the
> class factory for you and you do not need to implement it
> yourself. Read Roman's latest post, who knows about ATL.
>
> --
> // Alessandro Angeli
> // MVP :: DirectShow / MediaFoundation
> // mvpnews at riseoftheants dot com
> //http://www.riseoftheants.com/mmx/faq.htm
Ok. I followed Roman's example and removed my mods and all works
great. Thanks everyone for the help!
Mike
date: Wed, 17 Sep 2008 10:41:31 -0700 (PDT)
author: mike
|
|