I have a simple test driver that reproduces it, but I haven't found a way to
attach files to these posts - if the full test code and library would help
and there's an email address I can send it to, let me know.
Thanks for your help,
G.
This is the C# code that appears to leak:
amespace SonicExample
{
/// <summary>
///
/// </summary>
public class MessageListener : CSLEAKTESTVS6Lib.IJMSMessageListener
{
private int msgCount = 0;
public MessageListener()
{
}
/// <summary>
/// This called by the JMSCom frame work when a mesage is received
/// </summary>
/// <param name="pJMSMessage"></param>
[MTAThread]
public void onMessage(CJMSMessage pJMSMessage)
{
System.Runtime.InteropServices.Marshal.ReleaseComO bject(pJMSMessage);
pJMSMessage = null;
GC.Collect();
++msgCount;
if ((msgCount % 1000) == 0)
Console.WriteLine ("Message {0}", msgCount);
}
}
}
This is the code, inside the COM library, that registers and fires
callbacks, respectively - this is fairly boilerplate stuff and works
correctly if the COM client is C++, or C# compiled as debug.
// register the callback
if (pListener != NULL)
{
hr = AtlAdvise (thisUnknown,
listenerUnknown,
IID_IJMSMessageListener,
&m_MessageListenerCookie);
}
// The callback routine
// messageDelivery and Fire_onMessage get called repeatedly.
int CJMSTopicSubscriber::messageDelivery()
{
IJMSMessage *jmsMessage = NULL;
HRESULT hr = S_OK;
// It has been verified that jmsMessage does not leak
jmsMessage = new CComObject<CJMSMessage>();
if (jmsMessage != NULL)
{
// If all went well return the newly created JMS COM object
jmsMessage->AddRef();
}
else
{
fprintf (stderr, _T("Failed to create JMS Message COM Object") );
return -1;
}
if (SUCCEEDED(hr))
{
hr = Fire_onMessage(jmsMessage);
if (FAILED(hr))
{
fprintf (stderr, _T("Failed to send asynch message") );
return -1;
}
jmsMessage->Release();
jmsMessage = NULL;
}
else
{
fprintf (stderr, _T("Failed to create COM message wrapper") );
return -1;
}
return 0;
}
// Fire event.
HRESULT Fire_onMessage(IJMSMessage * pMessage)
{
HRESULT ret;
T* pT = static_cast<T*>(this);
int nConnectionIndex;
int nConnections = m_vec.GetSize();
for (nConnectionIndex = 0; nConnectionIndex < nConnections;
nConnectionIndex++)
{
pT->Lock();
CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
pT->Unlock();
IJMSMessageListener* pIJMSMessageListener =
reinterpret_cast<IJMSMessageListener*>(sp.p);
if (pIJMSMessageListener != NULL)
ret = pIJMSMessageListener->onMessage(pMessage);
}
return ret;
}
"Nicholas Paldino [.NET/C# MVP]" wrote:
Giovanni,
Can you post the test case?
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com
"Giovanni Boschi" <Gi************@discussions.microsoft.com> wrote in
message news:F3**********************************@microsof t.com... We have found a memory leak when using a COM library with a C#
application.
The leak appears only if the C# application is compiled with the /optimize
flag. It goes away when the C# application is compiled with the /debug
flag.
The COM library is coded to fire asynchronous events, which are handled by
the C# application. It is in the firing and handling of these events that
the leak occurs.
Why does the optimized application leak while the debug application does
not?
Is there a fix available?
Is there another way to do asynchronous event handling that will
circumvent
this problem?
Attached is a small test case that recreates the problem. The only code
of
real interest in the COM library is the event firing code. If the problem
that we see is in the COM library, it would have to be in this piece of
code.
However, this code is more or less the output of a wizard, it is pretty
standard stuff. The C# application is also trivial, with the only item of
any real interest being the event handler. Once again, the code has been
pared down to the point of being trivial. Any insights into asynchronous
event handling through an interop assembly is appreciated.
Thanks,
Giovanni Boschi
Sonic Software Corporation