I have a VC++ client that creates a COM object that is implemented in C#.
The problem is the COM object doesn't get released, so I get a memory leak.
I have no problems creating the COM object and getting a pointer to the
required interface (IATImportFilter) in the client:
COleDispatchDriver* resultInterface = new COleDispatchDriver;
if ( resultInterface == NULL ) return FALSE;
COleException oOleException;
BOOL success = resultInterface->CreateDispatch( progID, &oOleException );
IUnknown *p;
if ( resultInterface->m_lpDispatch->QueryInterface( *pRequiredInterface,
(void**)&p ) != S_OK )
where prodID ("SI.ValidatorImport") is the name of COM object.
My C# COM object class is declared like this:
[ClassInterface(ClassInterfaceType.None)]
[ProgId("SI.ValidatorImport")]
public class ValidatorImport : IATImportFilter
{
The object is being released in the client like this:
((IUnknown*) pIF)->Release();
pIF = NULL;
The call to Release() on the interface does not actually destroy the object.
It doesn't call the destructor of my COM object. I tried putting a
breakpoint in there and even added a MessageBox() call but the program just
doesn't go in there.
Not sure why this happening. Since every interface supports IUnkown,
Release() should release the COM object. The COM object is only created
once.
I'm new to C# so I would appreciate some help. 18 5864
>The call to Release() on the interface does not actually destroy the object. It doesn't call the destructor of my COM object.
Since it's a managed object it will eventually be cleaned up by the
garbage collector.
Mattias
--
Mattias Sjögren [MVP] mattias @ mvps.org http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
In message <jr********************@biscit.net>, techie
<te****@nospam.biz> writes The call to Release() on the interface does not actually destroy the object. It doesn't call the destructor of my COM object. I tried putting a breakpoint in there and even added a MessageBox() call but the program just doesn't go in there.
Not sure why this happening. Since every interface supports IUnkown, Release() should release the COM object. The COM object is only created once.
As I understand it, when you call Release(), you're calling it on a
COM-callable wrapper, not on the object itself. The COM callable wrapper
reference counts as you would expect a COM object to. When all
references are released, it releases its own reference to the object you
wrote in C#, which is then available for garbage collection. This will
happen at some point, but not necessarily when you expect it to. So, you
don't get deterministic finalisation of your C# object. You *may* get DF
of the wrapper, the documentation I've seen isn't clear on whether it is
destroyed immediately you are done with it It's pinned on a non GC'd
heap, again AIUI, so presumably it is destroyed immediately in the
normal COM fashion.
You probably don't have a memory leak, you more than likely have an
unreferenced object sat waiting to be GC'd.
--
Steve Walker
"Steve Walker" <st***@otolith.demon.co.uk> wrote in message
news:pI**************@otolith.demon.co.uk... You probably don't have a memory leak, you more than likely have an unreferenced object sat waiting to be GC'd.
Is there any I can force GC? Maybe if my class also implements IDisposable
I can call dispose from my client?
"Mattias Sjögren" <ma********************@mvps.org> wrote in message
news:uf*************@TK2MSFTNGP15.phx.gbl... The call to Release() on the interface does not actually destroy the
object.It doesn't call the destructor of my COM object.
Since it's a managed object it will eventually be cleaned up by the garbage collector.
The call to Release() on my interface pointer returns 0 - the reference
count on the interface - which indicates the COM object should have been
released or at least queued to be released by the GC. When VC++ debugger
halts it reports a lot of memory leaks which worries me.
Can I assume the COM object is released by the GC eventually? It must
happen some time after my VC++ client closes. Is there any way of forcing
the GC to delete my object immediately from my client? The call to Release() on my interface pointer returns 0 - the reference count on the interface - which indicates the COM object should have been released or at least queued to be released by the GC. When VC++ debugger halts it reports a lot of memory leaks which worries me.
The COM callable wrapper will be deleted, but the managed object is
just eligible for GC.
Can I assume the COM object is released by the GC eventually?
Yes
It must happen some time after my VC++ client closes.
It will happen the next time GC runs, or at process shutdown if the
executable calls CorExitProcess.
Is there any way of forcing the GC to delete my object immediately from my client?
Yes, with the GC class, but that doesn't mean it's a good idea to do
so.
And implementing IDisposable as you suggested in the other thread will
not affect GC, only let have deterministic cleanup of unmanaged
resources.
Mattias
--
Mattias Sjögren [MVP] mattias @ mvps.org http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
My VC++ 6 client doesn't make any GC.Collect() call. Its legacy code and I
don't want to change it.
I put a breakpoint in the destructor of my C# COM object class. I then ran
the C# project with the Start Application set to my VC++ client. At no
point did the program ever break into my breakpoint which implies the object
never got deleted. Why is that? Doesn't the GC run every now and then?
Does it only run when the memory usage of the machine reaches a high level?
In this particular solution, my C# COM object will be created via a C++ COM
object. A C# web service will create the C++ COM object. After I'm
finished with the COM object I can call GC.Collect() which will force
garbage collection. I'm just concerned my web server will run out of
memory. This is an important project and there are going to be a large
number of users.
Object "Finalizers" (also called destructor) are executed by/on the
finalizer thread, at some point in time, after the GC has run for the second
time after the object became eligible for collecting.
Note however that when your object has been instantiated in a STA thread,
this thread needs to pump the window message queue, failing to do so will
block the finalizer thread.
So first thing you should do is; check the apartment you are running in, if
it's a STA change it to MTA, and make sure your object is thread safe.
Willy.
"techie" <te****@nospam.biz> wrote in message
news:u7********************@biscit.net... My VC++ 6 client doesn't make any GC.Collect() call. Its legacy code and I don't want to change it.
I put a breakpoint in the destructor of my C# COM object class. I then ran the C# project with the Start Application set to my VC++ client. At no point did the program ever break into my breakpoint which implies the object never got deleted. Why is that? Doesn't the GC run every now and then? Does it only run when the memory usage of the machine reaches a high level?
In this particular solution, my C# COM object will be created via a C++ COM object. A C# web service will create the C++ COM object. After I'm finished with the COM object I can call GC.Collect() which will force garbage collection. I'm just concerned my web server will run out of memory. This is an important project and there are going to be a large number of users.
My VC++ 6 client is a normal .exe application. No MTA here. Could this be
reason for my memory leak?
However, my C++ COM object, which can be created from a ASP.NET web page, is
MTA. This COM object in turn will create my new C# object. I will test if
the destructor is called in this case.
"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:uO**************@TK2MSFTNGP10.phx.gbl... Object "Finalizers" (also called destructor) are executed by/on the finalizer thread, at some point in time, after the GC has run for the
second time after the object became eligible for collecting. Note however that when your object has been instantiated in a STA thread, this thread needs to pump the window message queue, failing to do so will block the finalizer thread. So first thing you should do is; check the apartment you are running in,
if it's a STA change it to MTA, and make sure your object is thread safe.
Willy.
Even 'normal' applications must initialize the thread to enter an apartment
before they can create COM instances and use their interfcaces. Question
is - what do you mean with a normal exe? Does it initialize the thread by
calling CoInitialize(Ex) to enter an STA or an MTA? And more importantly,
does it pump messages (all windows programs pump the message queue as part
of their UI message loop, console style applications don't pump however).
I'm not sure what you mean with your C++ object is MTA, COM objects can have
a 'threadingmodel' apartment, both and free, if no threadingmode is
specified the object lives in an OLE supplied host apartment.
'apartment' requires a STA to live in, 'both' can live in a STA as well as a
MTA while 'free' requires a MTA.
MTA initialized threads don't need to pump messages.
If your C++ COM is marked 'apartment' in the registry it must run in a
asp.net application with <%@ page aspcompat=true %> attribute set.
Willy.
"techie" <te****@nospam.biz> wrote in message
news:qK********************@biscit.net... My VC++ 6 client is a normal .exe application. No MTA here. Could this be reason for my memory leak?
However, my C++ COM object, which can be created from a ASP.NET web page, is MTA. This COM object in turn will create my new C# object. I will test if the destructor is called in this case.
"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message news:uO**************@TK2MSFTNGP10.phx.gbl... Object "Finalizers" (also called destructor) are executed by/on the finalizer thread, at some point in time, after the GC has run for the second time after the object became eligible for collecting. Note however that when your object has been instantiated in a STA thread, this thread needs to pump the window message queue, failing to do so will block the finalizer thread. So first thing you should do is; check the apartment you are running in, if it's a STA change it to MTA, and make sure your object is thread safe.
Willy.
In message <GZ********************@biscit.net>, techie
<te****@nospam.biz> writes "Steve Walker" <st***@otolith.demon.co.uk> wrote in message news:pI**************@otolith.demon.co.uk... You probably don't have a memory leak, you more than likely have an unreferenced object sat waiting to be GC'd.
Is there any I can force GC?
You can, but you probably shouldn't. The algorithm for garbage
collection itself is well documented. I can't find similar documentation
for the *scheduling* of garbage collection, but I get the impression
from its behaviour that it works on the principle that when there is
plenty of memory still free, CPU cycles should not be wasted on
recovering what has been used.
--
Steve Walker
I tried changing the 'normal' AfxOleInit() call to CoInitializeEx( NULL,
COINIT_MULTITHREADED) but it made no difference.
Coming from a C++ background I am used to all allocated memory being
released when an application closes down. If my main application is in C# I
can call Dispose() on the object but I can't in this case.
It's getting confusing, it would suggest you explain in detail your exact
scenario.
I see you called AfxOleInit() initially, that means the application is a MFC
application right? But what kind of application is it, a windows application
or something else, or simply put - does it have a UI?
If it has a UI you MUST not change the threads apartment to MTA, you must
keep the call to AfxOleInit.
Second, what kind of COM object are you creating from this C++ application;
1- a native C++ COM object, or
3- a native COM object creating a .NET COM object, or
2- a .NET COM object .
If it's 1 or 2, and the native COM object's 'threadingmodel' is set to
'Apartment', the object will be created on a STA thread no matter how you
initialize the (main) thread. And that thread must pump the message queue,
that's why I asked if it's a windows type client (having a UI). In case 2,
both objects will be created in the same apartment - so it's the native COM
objects who determines the apartment type.
In case 3, the 'COM' object will live in the creators apartment irrespective
it's type, but I can't stress it enough, - STA threads must pump messages,
and UI threads do have a message pump, non UI threads don't!
Note that in .NET the memory will also be released when the application
closes down.
I'm also not clear why you have a destructor defined for your "COM" class,
what is it used for?
A general rule is to avoid finalizers, unless your object is disposable
(implements IDisposable) and the destructor is only used as a safety net.
Willy.
"techie" <te****@nospam.biz> wrote in message
news:ar********************@biscit.net... I tried changing the 'normal' AfxOleInit() call to CoInitializeEx( NULL, COINIT_MULTITHREADED) but it made no difference.
Coming from a C++ background I am used to all allocated memory being released when an application closes down. If my main application is in C# I can call Dispose() on the object but I can't in this case.
The main application is an MFC Windows application with a UI. The main MFC
application creates a COM object. The COM object is a C# .NET COM object.
Therefore, my COM object is a STA thread? How do I get my COM object to
pump the message queue?
"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:%2***************@TK2MSFTNGP09.phx.gbl... It's getting confusing, it would suggest you explain in detail your exact scenario. I see you called AfxOleInit() initially, that means the application is a
MFC application right? But what kind of application is it, a windows
application or something else, or simply put - does it have a UI? If it has a UI you MUST not change the threads apartment to MTA, you must keep the call to AfxOleInit.
Second, what kind of COM object are you creating from this C++
application; 1- a native C++ COM object, or 3- a native COM object creating a .NET COM object, or 2- a .NET COM object .
If it's 1 or 2, and the native COM object's 'threadingmodel' is set to 'Apartment', the object will be created on a STA thread no matter how you initialize the (main) thread. And that thread must pump the message queue, that's why I asked if it's a windows type client (having a UI). In case 2, both objects will be created in the same apartment - so it's the native
COM objects who determines the apartment type. In case 3, the 'COM' object will live in the creators apartment
irrespective it's type, but I can't stress it enough, - STA threads must pump messages, and UI threads do have a message pump, non UI threads don't!
Note that in .NET the memory will also be released when the application closes down. I'm also not clear why you have a destructor defined for your "COM" class, what is it used for? A general rule is to avoid finalizers, unless your object is disposable (implements IDisposable) and the destructor is only used as a safety net.
Willy.
"techie" <te****@nospam.biz> wrote in message news:ar********************@biscit.net...I tried changing the 'normal' AfxOleInit() call to CoInitializeEx( NULL, COINIT_MULTITHREADED) but it made no difference.
Coming from a C++ background I am used to all allocated memory being released when an application closes down. If my main application is in
C# I can call Dispose() on the object but I can't in this case.
It sounds to me as if a quick primer on how the garbage collector works
might be useful to you. Here's a pretty good article: http://msdn.microsoft.com/msdnmag/issues/1100/gci/
In general:
Avoid calling GC.Collect() in production code -- trying to manually control
the GC will usually do more harm than good. (GC.Collect() can be useful in
testing scenarios, though).
Avoid using a Finalizer (destructor in C#) -- only use them if you need to
release some kind of unmanaged resource, like a handle.
IDisposable probably isn't what you think it is. You use it to provide a
deterministic way to call the finalizer (but you probably don't want to use
a finalizer).
Here's some additional reading: http://www.bluebytesoftware.com/blog...3-20c06ae539ae
A whole catalog of links: http://blogs.msdn.com/clyon/archive/...14/229477.aspx
"techie" <te****@nospam.biz> wrote in message
news:GZ********************@biscit.net... "Steve Walker" <st***@otolith.demon.co.uk> wrote in message news:pI**************@otolith.demon.co.uk... You probably don't have a memory leak, you more than likely have an unreferenced object sat waiting to be GC'd.
Is there any I can force GC? Maybe if my class also implements IDisposable I can call dispose from my client?
"techie" <te****@nospam.biz> wrote in message
news:Ee********************@biscit.net... The main application is an MFC Windows application with a UI. The main MFC application creates a COM object. The COM object is a C# .NET COM object. Therefore, my COM object is a STA thread? How do I get my COM object to pump the message queue?
Ok, its a MFC windows application creating a .NET COM object.
1. You don't have to pump messages, like I said this is handled by the UI
thread.
2. You COM object will live in the same STA thread as the UI.
3. COM objects are released when you call Release() on their inferfaces.
4. The .NET object will be collected when the GC runs (for objects without
destructors), or when the finalizer runs (for objects that have destructors
but not implementing IDisposable). Note the the finalizer runs on a
finalizable object after the second sweep of the GC. If this object is the
sole .NET COM object in the process chances are that the GC never runs, so
the finalizer will not run either, in that case the finalizer will run when
the process shuts down.
So I suggest you apply the Disposing pattern and remove the finalizer
(destructor).
Willy.
Can you please check my code for the Disposing pattern. I'm still getting a
memory leak. Dispose nevers gets called. I've removed the destructor
(~Import).
[ClassInterface(ClassInterfaceType.None)]
[ProgId("SI.Import")]
public class Import :IImportFilter, IDisposable
{
Session m_Session;
Content m_Content;
bool disposed = false;
..
..
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
ComHelper.SafeReleaseComObject(m_Content);
ComHelper.SafeReleaseComObject(m_Session);
}
disposed = true;
}
}
}
There are two unmanaged COM objects that need to be destroyed.
..
"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:OJ**************@TK2MSFTNGP09.phx.gbl... "techie" <te****@nospam.biz> wrote in message news:Ee********************@biscit.net... The main application is an MFC Windows application with a UI. The main MFC application creates a COM object. The COM object is a C# .NET COM
object. Therefore, my COM object is a STA thread? How do I get my COM object to pump the message queue?
Ok, its a MFC windows application creating a .NET COM object. 1. You don't have to pump messages, like I said this is handled by the UI thread. 2. You COM object will live in the same STA thread as the UI. 3. COM objects are released when you call Release() on their inferfaces. 4. The .NET object will be collected when the GC runs (for objects without destructors), or when the finalizer runs (for objects that have
destructors but not implementing IDisposable). Note the the finalizer runs on a finalizable object after the second sweep of the GC. If this object is the sole .NET COM object in the process chances are that the GC never runs, so the finalizer will not run either, in that case the finalizer will run
when the process shuts down. So I suggest you apply the Disposing pattern and remove the finalizer (destructor).
Willy.
The CCW will not call Dispose() automatically when it's ref. count reaches
0, your client has to call Dispose() explicitly just like any other managed
client should do, I guess you don't call Dispose() from the client.
Also note that calling Dispose won't free the "Import" 'managed COM'
object, this is done at the next GC run (non-deterministically), I hope this
is not the 'memory leak' your are referring to - this is not a memory leak
but the normal behavior.
I also suppose that SafeReleaseComObject is used to eagerly release other
unmanaged resources, if not you shouldn't implement IDisposable at all.
Willy.
"techie" <te****@nospam.biz> wrote in message
news:i7********************@biscit.net... Can you please check my code for the Disposing pattern. I'm still getting a memory leak. Dispose nevers gets called. I've removed the destructor (~Import).
[ClassInterface(ClassInterfaceType.None)] [ProgId("SI.Import")] public class Import :IImportFilter, IDisposable { Session m_Session; Content m_Content; bool disposed = false; .. .. public void Dispose() { Dispose(true); }
protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { ComHelper.SafeReleaseComObject(m_Content); ComHelper.SafeReleaseComObject(m_Session); } disposed = true; } }
}
There are two unmanaged COM objects that need to be destroyed. .
"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message news:OJ**************@TK2MSFTNGP09.phx.gbl... "techie" <te****@nospam.biz> wrote in message news:Ee********************@biscit.net... > The main application is an MFC Windows application with a UI. The main > MFC > application creates a COM object. The COM object is a C# .NET COM object. > Therefore, my COM object is a STA thread? How do I get my COM object > to > pump the message queue? > >
Ok, its a MFC windows application creating a .NET COM object. 1. You don't have to pump messages, like I said this is handled by the UI thread. 2. You COM object will live in the same STA thread as the UI. 3. COM objects are released when you call Release() on their inferfaces. 4. The .NET object will be collected when the GC runs (for objects without destructors), or when the finalizer runs (for objects that have
destructors but not implementing IDisposable). Note the the finalizer runs on a finalizable object after the second sweep of the GC. If this object is the sole .NET COM object in the process chances are that the GC never runs, so the finalizer will not run either, in that case the finalizer will run when the process shuts down. So I suggest you apply the Disposing pattern and remove the finalizer (destructor).
Willy.
OK, I will call Dispose() from my MFC client. Thanks for your help so far.
Is actually possible to QueryInterface for IDisposable?
If I have an ASP.NET application, instead of my MFC client, that creates a
C++ COM object which in turn creates my C# COM object do I have to implement
the IDisposable interface? Isn't this necessary for the GC to destroy all
unreferenced objects? Or do I just call Dispose() explicitly like in the
MFC client?
"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:Oy*************@tk2msftngp13.phx.gbl... The CCW will not call Dispose() automatically when it's ref. count reaches 0, your client has to call Dispose() explicitly just like any other
managed client should do, I guess you don't call Dispose() from the client. Also note that calling Dispose won't free the "Import" 'managed COM' object, this is done at the next GC run (non-deterministically), I hope
this is not the 'memory leak' your are referring to - this is not a memory leak but the normal behavior. I also suppose that SafeReleaseComObject is used to eagerly release other unmanaged resources, if not you shouldn't implement IDisposable at all.
Willy. This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: lylefair |
last post by:
Can you post code, or a reference to a md? or ad? file on a website,
where object variables are not released when they go out of scope and
cause a problem, (but causing a problem is extraneous to...
|
by: Sunny |
last post by:
Hi,
I have to implement client/server application. The client have to
instaniate an remoting object via http and pass some auth info. If the
auth is OK, the client should invoke a method (or...
|
by: Steven Blair |
last post by:
Hi,
Quick overview of the problem:
public bool Something( out DataSet ds )
{
bool ret=false;
try
{
|
by: VinDotNet |
last post by:
Here's the Scenario I am facing:
I've got a winform managed c++ client which connects to my managed
COM+ server application (by making createinstance, then typecasting
the object to an interface,...
|
by: david.kao |
last post by:
Hi All:
I am creating a COM+ Pool object in C#. I set up the following attributes:
JIT (true),Pool size; and at the end of each public method I called
ContextUtil.DeactivateOnReturn=true to set...
|
by: Michael Moreno |
last post by:
Hello,
In a class I have this code:
public object Obj;
If Obj is a COM object I would like to call in the Dispose() method the
following code:
...
|
by: FishVal |
last post by:
Windows Script Host Object library.
Full name: Windows Script Host Object Model
LibName: IWshRuntimeScripting
Location: ...\WINDOWS\system32\wshom.ocx
The present tip is closely related to...
|
by: abhimanyu |
last post by:
I have a method Marshal.IsComObject(...) that returns TRUE if an
object is a COM object.
I have an object of Excel.Worksheet that I released using
Marshal.ReleaseComObject(...). I want to iterate...
|
by: Raymond Chiu |
last post by:
Dear all,
I have written the following code in the button click event but find that
excel session object always remain in the server as seen from taskmanager.
Do you know why?...
|
by: emmanuelkatto |
last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud.
Please let me know.
Thanks!
Emmanuel
|
by: Sonnysonu |
last post by:
This is the data of csv file
1 2 3
1 2 3
1 2 3
1 2 3
2 3
2 3
3
the lengths should be different i have to store the data by column-wise with in the specific length.
suppose the i have to...
|
by: Hystou |
last post by:
There are some requirements for setting up RAID:
1. The motherboard and BIOS support RAID configuration.
2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
|
by: Hystou |
last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
|
by: jinu1996 |
last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
|
by: Hystou |
last post by:
Overview:
Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
|
by: tracyyun |
last post by:
Dear forum friends,
With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
|
by: agi2029 |
last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
|
by: conductexam |
last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
| |