COM Events passing Object as parameter (problem)

J

Jayme Pechan

I have a ATL COM object that is loaded through Interop in a C# application.
The COM object fires an event and one of the parameters is another object
created inside the object. This object has a property on it that is also
another object.
private void pIObj_EventProc(MObj.MainObj pObj)
{
MObj.Obj mainobj = pObj.Obj;
// IF I DON'T DO THE NEXT LINE, THE APPLICATION HANGS AT SOME LATER TIME
// THE UI DOESN'T EVEN UPDATE.
System.Runtime.InteropServices.Marshal.ReleaseComObject(mainobj);
}

Property in ATL Object that returns another object...
HRESULT CMainObj::get_Obj(IObj** pVal)
{
IObj* pIObj= NULL;
CComObject<CObj>* pObj;
if (S_OK == CComObject<CObj>::CreateInstance(&pObj)
&& S_OK == pObj->QueryInterface(IID_IObj, (void**)&pIObj))
{
*pVal = pIObj;
return S_OK;
}
}

I don't fully understand interop but I'm thinking this could be the source
of my problem. Is there a way to make this reliable from the COM object
perspective? I'd rather not require the user to do the ReleaseComObject in
order to prevent their application from hanging at some random time.
Everything works correctly if the host is C++ or JScript or other such
languages.

Any help would be appreciated.
 
M

Michael C

Jayme Pechan said:
I have a ATL COM object that is loaded through Interop in a C# application.
The COM object fires an event and one of the parameters is another object
created inside the object. This object has a property on it that is also
another object.
private void pIObj_EventProc(MObj.MainObj pObj)
{
MObj.Obj mainobj = pObj.Obj;
// IF I DON'T DO THE NEXT LINE, THE APPLICATION HANGS AT SOME LATER
TIME
// THE UI DOESN'T EVEN UPDATE.
System.Runtime.InteropServices.Marshal.ReleaseComObject(mainobj);
}

Here's my understanding of how com interop works. Dot net will create a
wrapper class around your com object. It will increment the ref count to 1
and keep it at 1 no matter how many references to the wrapper you create. It
will decrement it to zero if you call ReleaseComObject. You can still have
references to the wrapper after this but they will not function. If you do
the opposite and release all your references without calling
ReleaseComObject then the reference count will stay at 1 until the garbage
collector gets it. I'd say this is your problem in that the garbage
collector is causing your objects to be released in a different order to
what you'd normally expect. My guess would be that if you look in the code
for Release of your object you'll find the problem, maybe it references
another object there that has already been destroyed?

Michael
 
J

Jayme Pechan

Michael,

Thanks for the response. Its an interesting idea. In my test program,
there is nothing at all in the objects except the one property for returning
the other object. It still happens even if I store a reference to the
parameter object in a local variable in C# (should maintain the reference
count). In the ATL object, if I do not release the object after firing the
event, it works fine except that the MainObj never gets released in C# or
any other language.

Jayme
 
W

Willy Denoyette [MVP]

Jayme Pechan said:
I have a ATL COM object that is loaded through Interop in a C# application.
The COM object fires an event and one of the parameters is another object
created inside the object. This object has a property on it that is also
another object.
private void pIObj_EventProc(MObj.MainObj pObj)
{
MObj.Obj mainobj = pObj.Obj;
// IF I DON'T DO THE NEXT LINE, THE APPLICATION HANGS AT SOME LATER
TIME
// THE UI DOESN'T EVEN UPDATE.
System.Runtime.InteropServices.Marshal.ReleaseComObject(mainobj);
}

Property in ATL Object that returns another object...
HRESULT CMainObj::get_Obj(IObj** pVal)
{
IObj* pIObj= NULL;
CComObject<CObj>* pObj;
if (S_OK == CComObject<CObj>::CreateInstance(&pObj)
&& S_OK == pObj->QueryInterface(IID_IObj, (void**)&pIObj))
{
*pVal = pIObj;
return S_OK;
}
}

I don't fully understand interop but I'm thinking this could be the source
of my problem. Is there a way to make this reliable from the COM object
perspective? I'd rather not require the user to do the ReleaseComObject
in order to prevent their application from hanging at some random time.
Everything works correctly if the host is C++ or JScript or other such
languages.

Any help would be appreciated.

What kind of ATL object s this, a simple object or an AX control or...?
What kind of C# aplication is this? Where did you create the instance of the
COM object, which thread what's his threading attribute (STA/MTA)?
What exactly are you doing with the mainobj in your pIObj_EventProc?

Willy.
 
J

Jayme Pechan

As it turns out, one of the objects being passed into the event handler was
created on a thread declared as Apartment model and I hadn't implemented the
required message loop. Since in this case I could not implement a message
loop because of another message processing loop I was doing, I simply
declared the thread as free threaded and it works fine. I have to worry
about accessability of the members on these objects but since they are all
read only members, that was not difficult.
 

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