Using Types from the .NET Framework Class Library

Team-Fly    

 
.NET and COM Interoperability Handbook, The
By Alan Gordon
Table of Contents
Chapter Eight.  Advanced COM to .NET Interop

Using Types from the .NET Framework Class Library

The .NET Framework class library contains a rich set of classes, some of which have no analog in the various unmanaged class libraries that are available to programmers on Microsoft platforms, such as MFC, ATL, and the Visual Basic runtime. Unfortunately, many of these classes are invisible to COM.

Note

I was disappointed to find that the very useful and well-designed regular expression classes in the System.Text.RegularExpression namespace are COM invisible. I really wanted to use them as my demonstration for this section.


For the classes that are visible, you have three ways to use them from an unmanaged application: (1) You can register the assembly that contains the class, (2) you can call the ClrCreateManagedInstance method to create an instance of the class without registering its assembly, or (3) you can host the CLR and call one of the object creation methods in the CorRuntimeHost class. The code you write if you use one of the last two options is almost identical to what you would write if you used a user -defined class with the ClrCreateManagedInstance method or by hosting the CLR. The main difference is that, if you are using the mscorlib library, you do not have to use the full assembly name even though it resides in the GAC.

If you use either of the first two choices, you can only instantiate managed classes that have constructors that take no parameters. Hosting the CLR is more complicated, but it's the only way that you can create instances of classes that have parameterized constructors using the CreateInstance_3 overload of the CreateInstance method on the CorRuntimeHost class. (Remember that you cannot call the method that takes parameterized constructors from Visual Basic.) Let's look briefly at each of these techniques for using the classes in the .NET Framework class library from unmanaged code.

Registering the Assembly

Checking the registry on my machine showed that only the types in the System.EnterpriseServices namespace (these classes wrap the COM+ Services) are pre-registered by the setup program for the .NET Framework SDK. If you want to use any of the other managed types in the .NET Framework class library from your unmanaged applications using standard COM Activation functions, you will need to add the prerequisite registry entries for those types using the Assembly Registration Tool (regasm.exe). In order to use the Stack class, I registered the core library assembly ( mscorlib.dll ) by navigating to the directory where the .NET Framework library files reside ( D:\WINNT\Microsoft.NET\Framework\v1.0.3705 on my machine) and then running the following command:

 Regasm mscorlib.dll 

I then wrote the following code in Visual Basic 6, which uses the Stack class. To compile this code, I also had to reference the type library for the core library assembly by selecting Project References Common Language Runtime Library.

 1.  Private Sub Command1_Click() 2.      Dim aStack As Stack 3.      Set aStack = New Stack 4.      aStack.Push ("Shaquille ONeil") 5.      aStack.Push ("Kobe Bryant") 6.      aStack.Push ("Derek Fisher") 7.      aStack.Push ("Robert Horry") 8.      aStack.Push ("Rick Fox") 9.      MsgBox aStack.Count 10.     aStack.Pop 11.     MsgBox aStack.Pop 12. End Sub 

Line 2 declares an instance of the Stack class from the .NET Framework class library. Line 3 creates an instance of this class, and then lines 4 through 8 push the names of the starting lineup for the Los Angeles Lakers onto the stack. Line 9 displays the number of items on the stack (5), and then lines 10 and 11 pop two items off the stack. If you neglected to register the mscorlib.dll assembly, you will get a runtime error when you attempt to instantiate the stack object. Notice that the class interface for the Stack class is an empty interface that does not contain any methods. You are actually calling these methods through the IDispatch interface, so the Push, Count, or Pop methods will not appear in Visual Basic's IntelliSense.

Calling the ClrCreateManagedInstance Method

Another way to use types from the .NET Framework class library is to use the ClrCreateManagedInstance method. By using this method, you avoid having to register any of the class assemblies. The code here is very similar to the code that you looked at earlier that used ClrCreateManagedInstance with a user-defined managed class. The main difference is that you don't have to use the full name of the mscorlib assembly even though it resides in the GAC. In this case, I will demonstrate using the Stack class (late bound) from a Visual C++ 6 application.

 1.  void CUsecollectionsvcppDlg::OnButton1() 2.  { 3.      HRESULT hRes; 4.      DISPID dispid; 5.      BSTR bstrItem1, bstrItem2; 6.      CString strResult; 7.      OLECHAR *methodName=L"Push"; 8.      EXCEPINFO errorInfo; 9.      UINT intArg; 10.     VARIANT vntArgs[1], vntResult; 11.     DISPPARAMS param; 12.     param.cArgs=1; 13.     param.rgvarg=vntArgs; 14.     param.cNamedArgs=0; 15.     param.rgdispidNamedArgs=NULL; 16.     vntResult.vt=VT_R4; 17.     vntArgs[0].vt=VT_BSTR; 18. 19.     bstrItem1=SysAllocString(L"Alan Gordon"); 20.     vntArgs[0].bstrVal=bstrItem1; 21.     IDispatch *pObject; 22. 23.     hRes=::CoInitializeEx(NULL,COINIT_MULTITHREADED); 24. 25.     hRes=ClrCreateManagedInstance(26.       L"System.Collections.Stack,mscorlib", 27.       IID_IDispatch, (void **)&pObject); 28. 29.     hRes=pObject->GetIDsOfNames(IID_NULL,&methodName, 30.         1,GetUserDefaultLCID(),&dispid); 31. 32.     hRes=pObject->Invoke(dispid,IID_NULL, 33.         GetUserDefaultLCID(),DISPATCH_METHOD, 34.         &param,NULL,&errorInfo,&intArg); 35. 36.     bstrItem2=SysAllocString(L"Tamber Gordon"); 37.     vntArgs[0].bstrVal=bstrItem2; 38. 39.     hRes=pObject->Invoke(dispid,IID_NULL, 40.         GetUserDefaultLCID(),DISPATCH_METHOD, 41.         &param,NULL,&errorInfo,&intArg); 42. 43.     methodName=L"Count"; 44.     hRes=pObject->GetIDsOfNames(IID_NULL,&methodName, 45.         1,GetUserDefaultLCID(),&dispid); 46.     param.cArgs=0; 47.     hRes=pObject->Invoke(dispid,IID_NULL, 48.         GetUserDefaultLCID(),DISPATCH_PROPERTYGET, 49.         &param,&vntResult,&errorInfo,&intArg); 50. 51.     strResult.Format(52.       "Stack contains %d items", 53.       vntResult.lVal); 54.     AfxMessageBox(strResult); 55. 56.     methodName=L"Clear"; 57.     hRes=pObject->GetIDsOfNames(IID_NULL,&methodName, 58.         1,GetUserDefaultLCID(),&dispid); 59.     param.cArgs=0; 60.     hRes=pObject->Invoke(dispid,IID_NULL, 61.         GetUserDefaultLCID(),DISPATCH_METHOD, 62.         &param,NULL,&errorInfo,&intArg); 63. 64.     if (pObject != NULL) 65.        pObject->Release(); 66. 67.     SysFreeString(bstrItem1); 68.     SysFreeString(bstrItem2); 69. } 

Lines 3 through 11 declare variables . Lines 12 through 20 initialize the DISPPARAMS structure that will contain the parameters that I will pass to the Push method. On line 23, I enter the MTA. Lines 25 through 27 are the key lines in this example. There I call the ClrCreateManagedInstance method. The first parameter contains the type name and the partial name of the assembly. (Remember you don't need a full name for mscorlib.) Lines 29 and 30 get the DISPID for the Push method. I then call the Push method twice on lines 32 through 34 and again on lines 39 through 41. Lines 47 through 49 call the Count method, and Lines 51 through 54 display the value. Lines 56 through 62 call the Clear method on the stack to remove all the items that I pushed onto it. Finally, lines 64 through 68 clean up.

Remember that you need to add the directory that contains the include files for the .NET Framework SDK to the list of directories that Visual C++ will search for include files. You also need to add the directory that contains the library files for the .NET Framework SDK to the list of directories that Visual C++ will search for library files. In addition, you need to add the CLR execution engine (mscoree.lib) to the list of libraries that the project will link with.

Hosting the CLR

The two techniques that you have seen so far for using System classesthat is, registering the classes or calling ClrCreateManagedInstancehave one fatal flaw. You cannot use classes unless they have a constructor that takes no arguments. Unfortunately, that eliminates many useful classes in the .NET Framework class library from consideration for use.

As you learned in Chapter 3 when I discussed MSIL, the capacity parameter allows you to specify how large the stack's internal storage is initially. It's important to make this parameter as large as you expect the stack to be because expanding the internal storage is an expensive operation. Because of this, most of the collections in the .NET Framework class library support a constructor that allows you to specify the initial size of its internal buffer. The only way to call a parameterized constructor from unmanaged code is by hosting the CLR and using the CreateInstance_3 method on the AppDomain class. The code to do this is no different than the example that I looked at earlier that uses the CreateInstance_3 method, so I won't show the listing here. The difference is that you don't have to use the full name for the mscorlib library.


Team-Fly    
Top
 


. Net and COM Interoperability Handbook
The .NET and COM Interoperability Handbook (Integrated .Net)
ISBN: 013046130X
EAN: 2147483647
Year: 2002
Pages: 119
Authors: Alan Gordon

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net