--------------------------------------------------------------------------------------------

Copyright© 2001, Software Structures, Inc. All Rights Reserved.

---------------------------------------------------------------------------------------------

How to call a .NET Managed Code Component from an Unmanaged Code COM Client

 

---------------------------------

Note: This outline assumes that on your machine you have installed Windows 2000, Visual Studio 6 (with Service Pack 4) followed by an installation of Visual Studio .NET 7 Beta 1

---------------------------------

 

Walkthrough Summary

 

Using Visual Studio 7, a Visual Basic (Managed) Class Library project is created that exposes a .NET component class, and the new assembly (DLL) is built. Sn.exe is used to create a new global Id for the DLL, RegAsm.exe is used to create COM-compatible registry entries and GacUtil.exe is invoked to install the DLL into the .NET Global Assembly cache. As a first test, COM's OleView.exe is used to instance the new .NET component. For a more thorough test, 3 public methods are added to the .NET class and a COM client MFC Dialog application is generated using Visual Studio 6 MFC's AppWizard. We then show that the .NET component may be instanced and its methods called using ordinary COM client techniques based on ATL's CComPtr<...> smart pointer template class.

 

1.   Build a .NET managed component and server.

     Using Visual Studio 7 (.NET Beta 1) create a Visual Basic Class Library project "ManagedCodeVBClassLibrary0".

1a.  In the 'Solution Explorer' tab, rename Class1.vb to ManagedCodeVBClass0.vb

1b.  In the Solution Explorer tab click on 'ManagedCodeVBClass0.vb' then click the 'View Code' icon or press <F7>.

1c.  In the code window for ManagedCodeVBClass0.vb change the line "Public Class Class1" to "Public Class ManagedCodeVBClass0" to rename the .NET component.

1d. Open a Windows 2000 'Command Prompt' window (cmd.exe).

1e. At the '>' prompt issue the command 'SN.exe' (SN for "Strong [or Shared] Name").  Your 'Command Prompt' window should now display Usage information for SN.exe.  (if SN.exe does not execute, make sure it is installed on your system and its location is listed in your system's PATH environment variable.  Then, type again 'SN.exe' at the command prompt.)

1f.  You should find a description of SN.exe in 'Start- Menu/Programs/Microsoft .NET Framework SDK/Tools/Tools Guide'. Also search MSDN for "Shared Name Utility (Sn.exe)" for additional information.

1g.  Using SN.exe with command line parameter '-k' create a key file named 'ManagedCodeVBClassLibrary0.snk' and place it in the directory in which resides 'ManagedCodeVBClassLibrary0.vbproj'

1h.  In Vs7 Solution Explorer, right-click the 'ManagedCodeVBClassLibrary0' project and select the 'Properties' menu item.

1i.  Under 'Common Properties', left-click 'Sharing'. Check 'Generate strong name using:', Select radio button 'Key file' and browse for 'ManagedCodeVBClassLibrary0.snk' selecting it into the field for the Key file name.  At the bottom of the property page click 'Apply'.

1j.  Click 'OK' to close the 'ManagedCodeVBClassLibrary0 Property Pages' dialog.

1k.  Build assembly ManagedCodeVBClassLibrary0.dll

 

 

2.   Create Registry entries for ManagedCodeVBClassLibrary0.dll to enable COM clients.

2a.  At the command prompt (cmd.exe) issue the command:

    'regasm.exe ManagedCodeVBClassLibrary0.dll /tlb' to register to the registry your managed code Dll.

2b.  To verify the registration start OleView.exe, find       'ManagedCodeVBClassLibrary0.ManagedCodeVBClass0' under the '.NET Category' and double-click the item to create an instance of the class.  The check will fail with undocumented error code 0x80131522.

2c.  Regasm.exe is documented in MSDN and in the .NET Framework SDK.

 

 

3.   Install assembly ManagedCodeVBClassLibrary0.dll to the Global Assembly Cache.

3a.  At the command prompt (cmd.exe) issue the command:

    'gacutil.exe -i ManagedCodeVBClassLibrary0.dll', to install your managed code Dll.

3b.  To verify that installation, at the command prompt issue the command: 'gacutil.exe -l', ( 'l' is lower case 'L') and verify 'ManagedCodeVBClassLibrary0' in the generated list.

3c.  Gacutil.exe is documented in MSDN and in the .NET Framework SDK.

3d.  Repeat step 2b. which should now succeed.

 

 

From a formal point of view, we are done.  Your managed code component 'ManagedCodeVBClass0' may now be invoked by COM clients.  The following material is in the nature of additional proof.  There is still some concern about parameter marshalling across the managed <-> unmanaged boundary.

 

 

4.   Add three member functions to 'public class ManagedCodeVBClass0'

4a.  In Vs7 (.NET Beta 1) edit ManagedCodeVBClass0.vb adding to class ManagedCodeVBClass0, after the body of 'Public Sub New()', the following lines of code:

 

      Public Function TestFunc0() As Integer

        TestFunc0 = 4

      End Function

      Public Function TestFunc1(ByRef nRcvd As Integer) As Integer

        nRcvd = 5

        TestFunc1 = 6

      End Function

      Public Function TestFunc2(ByRef strRcvd As String) As String

        strRcvd = "aaaaa"

        TestFunc2 = "bbbbb"

      End Function

 

4b.  In Vs7 build ManagedCodeVBClassLibrary0.

4c.  Repeat Step 3 above, invoking Regasm.exe to update registration of the modified dll. You may also wish to View the new Typelibrary using Oleview.exe

 

 

5.   Create a COM client Application.

5a.  Using Visual Studio 6, create a Mfc Dialog displaying a button "Call Managed Component". Use default setting for the dialog.

5b.  Use the resource editor to add to the dialog a button with caption "Call Managed Component"

5c.  Using Class Wizard, add a function OnBUTTONCallManagedComponent() to receive BN_CLICKED events

5d. Edit the OnBUTTONCallManagedComponent() function adding the following block of code:

 

{  // Paste this block into your OnBUTTONCallManagedComponent() --- begin

 

  auto HRESULT hr= S_OK;

 

  {

        static bool bDidCallCoinitialize= false;

        if(!bDidCallCoinitialize) {

         hr = ::CoInitialize(NULL);

         //hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);

         ASSERT(S_OK == hr);

         bDidCallCoinitialize = true;

     }

  }

  

  auto CComPtr<ManagedCodeVBClassLibrary0::_ManagedCodeVBClass0>

         ccomptrManagedCodeVBClass0;

  try

  {

   // should this next call fail, you may need to reregister with Regasm

   // and reinstall into the global assembly cache.

   hr = ccomptrManagedCodeVBClass0.CoCreateInstance(

           __uuidof(ManagedCodeVBClassLibrary0::ManagedCodeVBClass0)

           );

        ASSERT(S_OK == hr);

   

        auto long lRet= ccomptrManagedCodeVBClass0->TestFunc0();

        ASSERT(4 == lRet);

 

        auto long lVal= 0;

        lRet = ccomptrManagedCodeVBClass0->TestFunc1(&lVal);

        ASSERT(5 == lVal);

        ASSERT(6 == lRet);

 

        auto BSTR strVal= ::SysAllocString(L"0123456789");

        auto _bstr_t bstrRet= ccomptrManagedCodeVBClass0->TestFunc2(&strVal);

        ASSERT(0 == wcscmp(L"aaaaa", strVal));

        ASSERT(0 == wcscmp(L"bbbbb", bstrRet));

 

        ::SysFreeString(strVal);

 

  }

  catch(...)

  {

        ASSERT(FALSE);

  }

 

      }  // Paste this block into your OnBUTTONCallManagedComponent() --- end

 

 

5e. You may need the following #includes at the top of your source file:

 

    //#include <objbase.h>  // for COINIT_MULTITHREADED

    #include <atlbase.h>  // for CComPtr

    #import "C:\WINNT\Microsoft.NET\Framework\v1.0.2204\mscorlib.tlb" \

        named_guids, no_namespace

        // for ISitePtr in ManagedCodeVBClassLibrary0.tlh

     #import "....\ManagedCodeVBClassLibrary0.tlb" named_guids 

 

5f.  Build your mfc dialog and using the Vs6 debugger step through the code.

 

 

Done.

 

Rafael Pena

rpenaphd@worldnet.att.net

2/20/2001

 

Keywords: HowTo, Walkthrough