DllCanUnloadNow function isn’t invoked after using classic COM components in .NET applications


 


COM Interop is a technic  for calling an unmanaged COM component from a .NET application, please refer to http://msdn.microsoft.com/en-us/magazine/dvdarchive/cc163494.aspx to learn how to implement it. DllCanUnloadNow is an important function which should be implemented and exported by the COM component.


However, you may be aware that the DllCanUnloadNow function isn’t invoked with the managed client if we don’t explicitly call CoUninitialize function. In this article, I’d like to explain why the DllCanUnloadNow function isn’t invokved.


How DllCanUnloadNow is invoked in native client


At first, let’s have a look at how the native client is implemented in C++ code.


void main(void)


{


     // Declare and HRESULT and a pointer to the Simple_ATL interface


     HRESULT              hr;


     IFirst_ATL      *IFirstATL = NULL;


 


     // Now we will intilize COM


     hr = CoInitialize(0);


 


     // Use the SUCCEDED macro and see if we can get a pointer to


     // the interface


     if(SUCCEEDED(hr))


     {


           hr = CoCreateInstance( CLSID_First_ATL, NULL, CLSCTX_INPROC_SERVER,


                IID_IFirst_ATL, (void**) &IFirstATL);


          


           // If we succeeded then call the AddNumbers method, if it failed


           // then display an appropriate message to the user.


           if(SUCCEEDED(hr))


           {


                long ReturnValue;


 


                hr = IFirstATL->AddNumbers(5, 7, &ReturnValue);


                cout << “The answer for 5 + 7 is: ” << ReturnValue << endl;


                hr = IFirstATL->Release();


           }


           else


           {


                cout << “CoCreateInstance Failed.” << endl;


           }


     }


     // Uninitialize COM


     CoUninitialize();


}


Please note, we never forget to invoke CoUninitialize function after we finish using the COM object.  The DllCanUnloadNow function will be triggered when calling CoUninitialize function, please refer to the following callstack.


0:000> k


ChildEBP RetAddr 


0012fe94 776bb927 simple_atl!DllCanUnloadNow [C:\comtest\COM_ATL_Object_Src\Simple_ATL.cpp @ 43]


0012fea8 77691b90 ole32!CClassCache::CDllPathEntry::CanUnload_rl+0x3b 


0012fef4 7769182a ole32!CClassCache::CleanUpDllsForApartment+0x12e


0012ff20 7769174c ole32!FinishShutdown+0xd7


0012ff40 776bce20 ole32!ApartmentUninitialize+0x94 


0012ff58 776bcdd2 ole32!wCoUninitialize+0x7d 


0012ff74 00401087 ole32!CoUninitialize+0x65 


 


How to make the DllCanUnloadNow be invoked in managed client


 


At first, let’s have a look at the common managed client code.


class Test


{


    static void Main()


    {


        MyCOMServerClass comServer = new MyCOMServerClass();


        comServer.MyCOMServerMethod();


        System.Runtime.InteropServices.Marshal.ReleaseComObject(comServer);


    }


}


In COM Interop, we don’t need to call CoInitialize function as the .NET framework will call it automatically. But .NET framework won’t call CoUninitialize automatically; this is why the DllCanUnloadNow function will never be triggered.


So, we need to call CoUninitialize explicitly by using P/Invoke of ole32.dll. Please refer to the following codes.


class Test


{


    [DllImport(“ole32.dll”)]


    extern static void CoUninitialize();


    static void Main()


    {


        MyCOMServerClass comServer = new MyCOMServerClass();


        comServer.MyCOMServerMethod();


        System.Runtime.InteropServices.Marshal.ReleaseComObject(comServer);


        CoUninitialize();


    }


}


 


Note: In this scenario, we need to call the CoUninitialize function when the application is closed. Although .NET will delay COM dll unloading, with CoUninitialize we can ensure the DllCanUnloadNow will be hit before process exits. To unload COM dll without such delay, please consider using CoFreeUnusedLibrariesEx(0,0).


References


DllCanUnloadNow Function: http://msdn.microsoft.com/en-us/library/ms690368(VS.85).aspx


CoUninitialize Function: http://msdn.microsoft.com/en-us/library/ms688715(VS.85).aspx


How to use COM components in Visual Studio .NET: http://support.microsoft.com/kb/816152


Beginner’s Tutorial: COM/ATL Simple Project: http://www.codeproject.com/KB/atl/com_atl.aspx


Improving Interop Performance: http://msdn.microsoft.com/en-us/library/ms998551.aspx


Regards,


Zhixing Lv

Comments (0)