COM Interop problem...

G

Guest

Hi,

Introduction:
*********************
I am writing a mixed mode application I have a COM module and a .NET module
that communicate with each other.
The COM exposes a custom sink interface, the .NET module implement the Sink
interface ( IUnknown based ) and the COM call the methods of this interface
asynchronously.

The problem:
*********************
When calling the sink methods on the .NET module from the context of a
managed thread ( the main app thread ) created by the .NET framework
everything works fine BUT when calling the sink methods ( implemented by the
managed module ) from an unmanaged thread that was created by the COM module
I get E_NOINTERFACE.

Note that The managed sink implementation is associated with the COM module
through an Advice( ISink sink, ref uint uiContext ) method.

What may cause this problem? I called CoInitializeEx on all of the new
unmanaged threads…

Following is a code snap of the two modules:

Unmanaged COM:
################################################
interface IMediaEvents
{
virtual HRESULT OnState(eState state, VARIANT &var) = 0;
};

Protected:
HRESULT Fire_OnState(IN eState state, IN VARIANT &var)
{
HRESULT hrRet = S_OK;
SinkVector_t::iterator itr = m_vecSink.begin();
while(itr != m_vecSink.end())
{
//////////////////////////////
// Returns E_NOINTERFACE!!!
if(FAILED((*itr)->OnState(state, var)))
hrRet = S_FALSE;
//////////////////////////////
itr++;
}
return hrRet;
}

Public:
STDMETHOD(Advise)(IMediaEvents* pSink,
ULONG* pulCookie)
{
…
while(itr != m_vecSink.end())
{
if(pSink == (*itr).p)
return HRESULT_FROM_WIN32(ERROR_ALREADY_CONNECTED);
itr++;
}
m_vecSink.push_back(spSink);
*pulCookie = (ULONG)spSink.p;
return S_OK;
}

STDMETHOD(Unadvise)(/*[in]*/ ULONG ulCookie)
{
…
}

Managed Sink
##############################
public class Form1 : System.Windows.Forms.Form
, StreamingServerLib.IMediaEvents
{
…
…
…
private void btnRecord_Click(object sender, System.EventArgs e)
{
if(null != m_RecordSession)
{
m_RecChan.Unadvise(m_uiRecCookie);
m_MediaBuffer.CloseSession(m_RecordSession);
m_RecordSession = null;
}
m_RecChan = null;
m_RecChan = m_MediaBuffer.CreateChan(txtOutputPath.Text, -1);
///////////////////////////////////////////////
// Connects with the COM object
m_uiRecCookie = m_RecChan.Advise(this);
…
m_RecordSession.Start(txtSourcePath.Text);
}

/////////////////////////////////////////////////////////////////
// Called by the COM only when executed from a managed thread
// when invoked by an unmanaged thread E_NOINTERFACE is returned
// to the unmanaged caller
public void OnState(StreamingServerLib.eState state,
object varParam)
{
…
}
…
…
};

Nadav
http://www.sophin.com
 
C

Carl Daniel [VC++ MVP]

Nadav said:
Hi,

Introduction:
*********************
I am writing a mixed mode application I have a COM module and a .NET
module that communicate with each other.
The COM exposes a custom sink interface, the .NET module implement
the Sink interface ( IUnknown based ) and the COM call the methods of
this interface asynchronously.

The problem:
*********************
When calling the sink methods on the .NET module from the context of a
managed thread ( the main app thread ) created by the .NET framework
everything works fine BUT when calling the sink methods ( implemented
by the managed module ) from an unmanaged thread that was created by
the COM module I get E_NOINTERFACE.

Note that The managed sink implementation is associated with the COM
module through an Advice( ISink sink, ref uint uiContext ) method.

What may cause this problem? I called CoInitializeEx on all of the new
unmanaged threads.

You need to marshall a pointer to the managed event consumer into your
native thread. See CoMarshalInterThreadInterfaceInStream and
CoGetInterfaceAndReleaseStream in MSDN.

-cd
 
G

Guest

Hi Carl,

Thanks for your responce, I wonder... why must I marshal the inteface? this
involve sending inter-thread windows messages and this may have impact on
performance... isn't there a way to call the method directly and letting my
code to manage synchronization issues [???]
 
W

Willy Denoyette [MVP]

Both caller and callee run on diffrerent threads and different apartments
(UI thread - STA) unmanaged thread (STA/MTA?), so you need to marshal.
One possible solution might be to create the object on a (managed) MTA
thread (if the object doesn't realy requires an STA! which I doubt) and
initialize your unmanaged threads to enter the one and only MTA. Sure, this
will require to marshal the calls to the UI thread when you need to update
the UI from the managed MTA thread.

Willy.

Nadav said:
Hi Carl,

Thanks for your responce, I wonder... why must I marshal the inteface?
this
involve sending inter-thread windows messages and this may have impact on
performance... isn't there a way to call the method directly and letting
my
code to manage synchronization issues [???]
--
Nadav
http://www.sophin.com


Carl Daniel said:
You need to marshall a pointer to the managed event consumer into your
native thread. See CoMarshalInterThreadInterfaceInStream and
CoGetInterfaceAndReleaseStream in MSDN.

-cd
 
G

Guest

Hi Willy,

Thanks for your responce, Well, setting the main thread to run as MTA
doesn't resolve the problem, still, E_NOINTERFACE is returned whn the
unmanaged COM calls the meneged object.
I wonder must this be a marshaling problem? if so, why does E_NOINTERFACE is
returned? what interface cannot be found on the managed object?

P.S.
How can associate a certain thread with a specific apartment???

Nadav
http://www.sophin.com


Willy Denoyette said:
Both caller and callee run on diffrerent threads and different apartments
(UI thread - STA) unmanaged thread (STA/MTA?), so you need to marshal.
One possible solution might be to create the object on a (managed) MTA
thread (if the object doesn't realy requires an STA! which I doubt) and
initialize your unmanaged threads to enter the one and only MTA. Sure, this
will require to marshal the calls to the UI thread when you need to update
the UI from the managed MTA thread.

Willy.

Nadav said:
Hi Carl,

Thanks for your responce, I wonder... why must I marshal the inteface?
this
involve sending inter-thread windows messages and this may have impact on
performance... isn't there a way to call the method directly and letting
my
code to manage synchronization issues [???]
--
Nadav
http://www.sophin.com


Carl Daniel said:
Nadav wrote:
Hi,

Introduction:
*********************
I am writing a mixed mode application I have a COM module and a .NET
module that communicate with each other.
The COM exposes a custom sink interface, the .NET module implement
the Sink interface ( IUnknown based ) and the COM call the methods of
this interface asynchronously.

The problem:
*********************
When calling the sink methods on the .NET module from the context of a
managed thread ( the main app thread ) created by the .NET framework
everything works fine BUT when calling the sink methods ( implemented
by the managed module ) from an unmanaged thread that was created by
the COM module I get E_NOINTERFACE.

Note that The managed sink implementation is associated with the COM
module through an Advice( ISink sink, ref uint uiContext ) method.

What may cause this problem? I called CoInitializeEx on all of the new
unmanaged threads.

You need to marshall a pointer to the managed event consumer into your
native thread. See CoMarshalInterThreadInterfaceInStream and
CoGetInterfaceAndReleaseStream in MSDN.

-cd
 
W

Willy Denoyette [MVP]

Nadav said:
Hi Willy,

Thanks for your responce, Well, setting the main thread to run as MTA
doesn't resolve the problem, still, E_NOINTERFACE is returned whn the
unmanaged COM calls the meneged object.
I wonder must this be a marshaling problem? if so, why does E_NOINTERFACE
is
returned? what interface cannot be found on the managed object?

P.S.
How can associate a certain thread with a specific apartment???

Nadav
http://www.sophin.com

Sorry, I only replied because you were asking about the
inter-thread/apartment marshaling issues (performance).
The E_NOINTERFACE is another issue, but it's hard to tell from the snippets
you posted what goes wrong other than - there is no such interface exposed.
Willy.
 
G

Guest

Hi Carl,

I have tried to use the technique you have suggested ( usage of
CoMarshalInterThre... ), BUT Still the problem persist...
Calling 'CoMarshalInterThreadInterfaceInStream' followed by a call to
'CoGetInterfaceAndReleaseStream' returns a pointer to an interface of the
correct type, actually the pointer returned by
'CoGetInterfaceAndReleaseStream' has the exact address of the one registered
with 'CoGetInterfaceAndReleaseStream'
My guess is that the interface isn't needed to be marshaled and as such an
pointer identical to the one registered with 'CoGetInterfaceAndReleaseStream'
is returned.
If my assumption is true there should be some-thing else causing this
problem, what is it????

Any help comment or remark would be appreciated.

Nadav
http://www.sophin.com
 
C

Carl Daniel [VC++ MVP]

Nadav said:
Hi Carl,

I have tried to use the technique you have suggested ( usage of
CoMarshalInterThre... ), BUT Still the problem persist...
Calling 'CoMarshalInterThreadInterfaceInStream' followed by a call to
'CoGetInterfaceAndReleaseStream' returns a pointer to an interface of
the correct type, actually the pointer returned by
'CoGetInterfaceAndReleaseStream' has the exact address of the one
registered with 'CoGetInterfaceAndReleaseStream'
My guess is that the interface isn't needed to be marshaled and as
such an pointer identical to the one registered with
'CoGetInterfaceAndReleaseStream' is returned.
If my assumption is true there should be some-thing else causing this
problem, what is it????

Any help comment or remark would be appreciated.

Just to be clear - you need to call 'CoMarshalInterThreadInterfaceInStream'
in the thread that loaded your DLL, and call
'CoGetInterfaceAndReleaseStream' in the thread that you created. Is that
what you tried? If so, the problem is clearly something other than
marshalling.

How have you associated the COM identity of the outbound interface with your
..NET sink? In the code snippets you posted, I don't see any of the COM
attributes decorating the class or the method, so I'm assuming that you've
just used tlbimp to generate an interop assembly for your native COM class.

Can you consume events from your COM class from another COM-based host, such
as JScript or ASP (not ASP.NET)?

-cd
 
M

Marcus Heege

The COM standard marshaler usually uses the type libraray. E_NOINTERFACE as
a result of a marshaling operation is often the result of missing type
library registration. Make sure the type library is registered, either via
regasm /tlb yourAsssembly.dll or via regtlb yourDllOrTlb.[dll|tlb].

Marcus Heege

Nadav said:
Hi,

Introduction:
*********************
I am writing a mixed mode application I have a COM module and a .NET
module
that communicate with each other.
The COM exposes a custom sink interface, the .NET module implement the
Sink
interface ( IUnknown based ) and the COM call the methods of this
interface
asynchronously.

The problem:
*********************
When calling the sink methods on the .NET module from the context of a
managed thread ( the main app thread ) created by the .NET framework
everything works fine BUT when calling the sink methods ( implemented by
the
managed module ) from an unmanaged thread that was created by the COM
module
I get E_NOINTERFACE.

Note that The managed sink implementation is associated with the COM
module
through an Advice( ISink sink, ref uint uiContext ) method.

What may cause this problem? I called CoInitializeEx on all of the new
unmanaged threads.

Following is a code snap of the two modules:

Unmanaged COM:
################################################
interface IMediaEvents
{
virtual HRESULT OnState(eState state, VARIANT &var) = 0;
};

Protected:
HRESULT Fire_OnState(IN eState state, IN VARIANT &var)
{
HRESULT hrRet = S_OK;
SinkVector_t::iterator itr = m_vecSink.begin();
while(itr != m_vecSink.end())
{
//////////////////////////////
// Returns E_NOINTERFACE!!!
if(FAILED((*itr)->OnState(state, var)))
hrRet = S_FALSE;
//////////////////////////////
itr++;
}
return hrRet;
}

Public:
STDMETHOD(Advise)(IMediaEvents* pSink,
ULONG* pulCookie)
{
.
while(itr != m_vecSink.end())
{
if(pSink == (*itr).p)
return HRESULT_FROM_WIN32(ERROR_ALREADY_CONNECTED);
itr++;
}
m_vecSink.push_back(spSink);
*pulCookie = (ULONG)spSink.p;
return S_OK;
}

STDMETHOD(Unadvise)(/*[in]*/ ULONG ulCookie)
{
.
}

Managed Sink
##############################
public class Form1 : System.Windows.Forms.Form
, StreamingServerLib.IMediaEvents
{
.
.
.
private void btnRecord_Click(object sender, System.EventArgs e)
{
if(null != m_RecordSession)
{
m_RecChan.Unadvise(m_uiRecCookie);
m_MediaBuffer.CloseSession(m_RecordSession);
m_RecordSession = null;
}
m_RecChan = null;
m_RecChan = m_MediaBuffer.CreateChan(txtOutputPath.Text, -1);
///////////////////////////////////////////////
// Connects with the COM object
m_uiRecCookie = m_RecChan.Advise(this);
.
m_RecordSession.Start(txtSourcePath.Text);
}

/////////////////////////////////////////////////////////////////
// Called by the COM only when executed from a managed thread
// when invoked by an unmanaged thread E_NOINTERFACE is returned
// to the unmanaged caller
public void OnState(StreamingServerLib.eState state,
object varParam)
{
.
}
.
.
};

Nadav
http://www.sophin.com
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top