Ureader.com  
Microsoft software help and Community
   home   |   control panel login   |   archive   |  
 
Windos
win32.3rdparty
win32.directx.audio
win32.directx.ddk
win32.directx.graphics
win32.directx.input
win32.directx.managed
win32.directx.misc
win32.directx.networking
win32.directx.sdk
win32.directx.video
win32.dirx.grap.shaders
win32.gdi
win32.international
win32.kernel
win32.messaging
win32.mmedia
win32.networks
win32.ole
win32.rtc
win32.tapi
win32.tapi.beta
win32.tools
win32.ui
win32.wince
win32.wmi
windows.mediacenter
winfx.aero
winfx.announcements
winfx.avalon
winfx.collaboration
winfx.fundamentals
winfx.general
winfx.indigo
winfx.sdk
winfx.winfs
  
 
date: Mon, 15 Sep 2008 16:01:13 -0700 (PDT),    group: microsoft.public.win32.programmer.directx.video        back       


DMO manually created for graph with wrapper?   
I have a DMO that I've created that I would like to use in a graph in
a 2nd application.  I would like to not have to register the DMO but
to create it while building the graph (create it internally to the 2nd
application).  It looks like the DMOWrapper can't take an instantiated
COM object but a ref to a classid to create the object itself.  Is
this the case?  Is it possible to create an instance of a DMO that's
not registered and use it in a graph?

Thanks,

Mike
date: Mon, 15 Sep 2008 16:01:13 -0700 (PDT)   author:   mike

Re: DMO manually created for graph with wrapper?   
On Mon, 15 Sep 2008 16:01:13 -0700 (PDT), mike wrote:

>  It looks like the DMOWrapper can't take an instantiated
> COM object but a ref to a classid to create the object itself.  Is
> this the case?  Is it possible to create an instance of a DMO that's
> not registered and use it in a graph?

AFAIK, you cannot make a DMO internal to an app.  You can do it with a
regular filter (source, transform, inplace, renderer, etc.).

-- 
Please read this before replying:
1. Dshow & posting help:  http://tmhare.mvps.org/help.htm
2. Trim & respond inline (please don't top post or snip everything)
3. Benefit others:  follow up if you are helped or you found a solution
date: Mon, 15 Sep 2008 18:16:40 -0600   author:   The March Hare [MVP] erland

Re: DMO manually created for graph with wrapper?   
From: "mike"

> I have a DMO that I've created that I would like to use
> in a graph in a 2nd application.  I would like to not
> have to register the DMO but to create it while building
> the graph (create it internally to the 2nd application).
> It looks like the DMOWrapper can't take an instantiated
> COM object but a ref to a classid to create the object
> itself.  Is this the case?  Is it possible to create an
> instance of a DMO that's not registered and use it in a
> graph?

It's an undocomented behavior, but IDMOWrapperFilter::Init() 
only uses the DMO's CLSID in CoCreateInstance() and ignores 
the category GUID.

So you should be able to use 
CoRegisterClassObject(CLSCTX_INPROC_SERVER,REGCLS_ MULTI_ 
SEPARATE) to register the DMO's IClassFactory internally, 
without globally registering the inproc server.

You can implement the class factory yourself or re-use the 
implementation in the BaseClasses or in ATL and so on.


-- 
// Alessandro Angeli
// MVP :: DirectShow / MediaFoundation
// mvpnews at riseoftheants dot com
// http://www.riseoftheants.com/mmx/faq.htm
date: Tue, 16 Sep 2008 06:54:40 -0400   author:   Alessandro Angeli

Re: DMO manually created for graph with wrapper?   
Hi,

> It's an undocomented behavior, but IDMOWrapperFilter::Init()
> only uses the DMO's CLSID in CoCreateInstance() and ignores
> the category GUID.

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.

Roman
date: Tue, 16 Sep 2008 09:32:09 -0700 (PDT)   author:   Roman Ryl...

Re: DMO manually created for graph with wrapper?   
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
date: Tue, 16 Sep 2008 12:53:08 -0400   author:   Alessandro Angeli

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?   
Mike,

As far as I can see you have ATL project. And you have a coclass
CSILKEncoderDMO with CLSID_SILKEncoderDMO. I assume this class has
its .rgs entry, corresponding OBJECT_ENTRY macro etc, so it is already
COM-instatiateable. In any event you don't need to
CComObject<CSILKEncoderDMO>::CreateInstance since you will have DMO
wrapper created an instance of the class internally as a part of Init
call. Note that your class will be created as aggregated so you must
not disable this functionality by ATL macro (I believe you don't).

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.

Certainly this allows third party to reuse your class similar way and
bypass the protection but it is required to know in advance correct
CLSID etc. If it is important to protect in a stricter way, you need
to remove OBJECT_ENTRY so that CoRegisterClassObject is not called
automatically for your class by ATL base. In this case you will need
to call it yourself before DMO Init call (as in your sample).

Roman
date: Tue, 16 Sep 2008 13:18:24 -0700 (PDT)   author:   Roman Ryl...

Re: DMO manually created for graph with wrapper?   
From: "Roman Ryl..."

> 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.

-- 
// Alessandro Angeli
// MVP :: DirectShow / MediaFoundation
// mvpnews at riseoftheants dot com
// http://www.riseoftheants.com/mmx/faq.htm
date: Tue, 16 Sep 2008 16:55:36 -0400   author:   Alessandro Angeli

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

Google
 
Web ureader.com


    COPYRIGHT 2007, YARDI TECHNOLOGY LIMITED, ALL RIGHT RESERVE  |   contact us