views:

122

answers:

1

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?

+3  A: 

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();
}
Arseny
+1 This is the solution. Com Callable Wrappers don't pay any attention to IDisposable. Here's some [explanation by Sam Gentile](http://radio-weblogs.com/0105852/stories/2002/12/21/comInteropNotFundamentallyFlawedButHard.html)
MarkJ
Thanks to you both, the link was also very helpful.
Andrew