Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Properly disposing C# objects when created via COM Interop

Im writing a C# class library component which is going to act as a TCP server. It will listen for and receive XML via a specific port, deserialize it and then raise events containing the resulting object as an event argument.

The class library itself will be consumed by a VB6 application which will receive and handle the events and associated COM visible class objects.

The TcpServer class wraps up the TcpListener functionalty and is not COM visible. This handles the connections and raises events dealing with connects, disconnects and received data.

sealed class TcpServer : IDisposable
{
    private readonly TcpListener tcpListener;
    private bool disposed = false;  

    public TcpServer(int port)
    {
        tcpListener = new TcpListener(IPAddress.Any, port);
        tcpListener.Start();
        tcpListener.BeginAcceptSocket(EndAcceptSocket, tcpListener);
    }

    ~TcpServer()
    {
        Dispose(false);
    }   

    // blah blah blah

    public void Dispose()
    {
        Dispose(true);
    }

    private void Dispose(bool disposing)
    {
        if (this.disposed == false)
        {
            if (disposing)
            {
                if (tcpListener != null)
                {
                    tcpListener.Stop();
                }
            }
            this.disposed = true;
        }
    }       
}

WUServer is the COM visible class that the VB6 application creates and uses. It wraps the TcpServer class and is responsible for deserializing any received data and raising the appropriate event with related event arguments.

public class WUServer : IWUServer
{
    private TcpServer tcpServer;

    public WUServer()
    {
        tcpServer = new TcpServer(12345);
        tcpServer.DataReceived += new EventHandler<DataReceivedEventArgs>(tcpServer_DataReceived);
        tcpServer.SocketConnected += new EventHandler<IPEndPointEventArgs>(tcpServer_SocketConnected);
        tcpServer.SocketDisconnected += new EventHandler<IPEndPointEventArgs>(tcpServer_SocketDisconnected);
    }
}

The problem I am having is that the TcpServer class is not being disposed of properly by the VB6 application. Setting the WUServer instance to Nothing before the application closes does not result in the disposal of the TcpServer class, it continues to hang on to the socket and results in errors if I attempt the run the VB6 application again.

If I consume the WUServer class from a C# application, everything is fine, Dispose is called on TcpServer and the socket is closed.

How should I ensure that the TcpServer class is properly disposed of when it is created indirectly by the VB6 application?

like image 940
Andrew Avatar asked Aug 02 '10 11:08

Andrew


People also ask

What does dispose () do in C#?

In the context of C#, dispose is an object method invoked to execute code required for memory cleanup and release and reset unmanaged resources, such as file handles and database connections.

Is dispose always called C#?

Dispose() will not be called automatically. If there is a finalizer it will be called automatically. Implementing IDisposable provides a way for users of your class to release resources early, instead of waiting for the garbage collector.

How do you dispose a variable in C#?

To free and reset the resources that are unmanaged like connections to the databases, files, etc., and to perform a cleanup of the memory, we make use of a function called dispose of () function in C#. The dispose() function in C# must implement the IDisposable interface.


1 Answers

you can add a public method to WUServer which you call explicitly in VBA inside of that method release your TCP server

void Close()
{
 tcpServer.Dispose();
}
like image 140
Arseny Avatar answered Oct 21 '22 15:10

Arseny