Accessing COM components from a serviced component is the same as accessing COM components from any .NET application. However, the RCWs referenced by serviced components should be strongly named. In this exercise, you'll learn how to use the command-line options of the Type Library Importer tool to create a strongly named RCW and use it from a serviced component.
Estimated time : 20 minutes
Launch a .NET command prompt by selecting Start, Programs, Microsoft Visual Studio .NET, Visual Studio .NET Tools, Visual Studio .NET Command Prompt.
Inside the command prompt window, navigate to the folder that contains the MyCustomer.dll COM library.
If you have already created the key file containing the public/private key pair in Step by Step 7.2 in Chapter 7, copy the key file 70310.snk to this directory. If you haven't created one before, issue the following command to create a pair of public/private keys:
sn k 70310.snk
Now, enter this command line to run the Type Library Importer tool to create a strongly named RCW:
tlbimp MyCustomer.dll /keyfile:70310.snk /out:NETSMyCustomer.dll
Create a Blank Solution named 310C08Exercises in the Visual Studio .NET IDE.
Add a Visual Basic .NET Class library named Exercise8-1 to the solution.
Right-click the References node in Solution Explorer and select Add Reference.
Click the Browse button in the Add Reference dialog box. Browse to the NETSMyCustomer.dll file that you created in step 4 and click Open. Click OK to add the reference to the project.
Add a reference to the System.EnterpriseServices library in the current project.
In the Solution Explorer, rename the default Class1.vb to BalanceSC.vb .
Open the BalanceSC.vb and replace the code with the following code:
Imports System Imports System.EnterpriseServices Imports NETSMyCustomer Namespace Exercise8_1 Public Interface IBalanceSC Function RetrieveBalance(_ ByVal custNumber As Short) As Decimal End Interface Public Class BalanceSC Inherits ServicedComponent Implements IBalanceSC Public Function BalanceSC() End Function Public Function RetrieveBalance(_ ByVal custNumber As Short) As Decimal _ Implements IBalanceSC.RetrieveBalance Dim b As Balances = New Balances() RetrieveBalance = b.GetBalance(_ custNumber) End Function End Class End Namespace
Open the AssemblyInfo.vb file in the project and add the following Imports directive:
Add assembly level attributes ApplicationName , Description and ApplicationActivation to the AssemblyInfo.vb as shown here:
<Assembly: ApplicationName(_ "Customer Balance Application")> <Assembly: Description("Retrieves the " & _ "customer balance from a COM component")> <Assembly: ApplicationActivation(_ ActivationOption.Library)>
Copy the 70310.snk key pair file to the solution folder. Change the AssemblyVersion and AssemblyKeyFile attributes in the AssemblyInfo.vb file as shown here:
<Assembly: AssemblyVersion("1.0")> <Assembly: AssemblyKeyFile(_ "..\..\..310.snk")>
Build the project. Exercise8-1.dll is generated, and a strong name is assigned to the file based on the specified key file.
Launch Visual Studio .NET command prompt and change the directory to the folder where the DLL file generated in step 15 resides. Issue the following command to install the assembly to the GAC:
gacutil /i Exercise8-1.dll
In the command prompt, issue the following command to install the service component assembly to the COM+ Catalog:
Add a new Visual Basic .NET Windows application named Exercise8-1Test to the solution.
Add references to the System.EnterpriseServices library and Exercise8-1 project in the current project.
Rename the form Form1 to Balance . Switch to code view and change all occurrences to Form1 to refer to Balance instead.
Place two Label controls, two TextBox controls ( txtCustomerNumber and txtBalance ), and a Button control ( btnGetBalance ), on the form. Arrange the controls as shown in Figure 8.5.
Switch to code view and add the following Imports directive:
Double-click the Button control and add the following code to its Click event handler:
Private Sub btnGetBalance_Click(_ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnGetBalance.Click Dim bsc As Exercise8_1.Exercise8_1. _ BalanceSC = _ New Exercise8_1.Exercise8_1. _ BalanceSC() Dim custNumber As Integer = _ Int16.Parse(_ txtCustomerNumber.Text) txtBalance.Text = _ bsc.RetrieveBalance(_ custNumber).ToString() End Sub
Set the form as the startup form for the project, and set Exercise8-1Test as the startup project.
Run the project. Enter a value between 1 to 10 in the first text box and click the Get Balance button to see that customer's balance. The balance is retrieved by a method call to the serviced component that in turn retrieves the balance from a method call to a COM component.
Name some reasons to use COM components in a .NET project.
You might use COM components in a .NET project because you need to migrate an existing application in small pieces or because the COM components contain unique functionality for which you do not have source code.
What is the purpose of an RCW?
RCWs provide a proxy between .NET applications and COM components. The RCW translates .NET calls into COM calls and returns the COM results as .NET results.
How do you create an RCW?
You can create an RCW by using the Type Library Importer tool or by adding a direct reference to the COM component.
What should you consider when choosing how to create an RCW?
When deciding how to create an RCW, you should consider whether you own the source code for the COM component, whether the RCW needs to go into the GAC, and how many .NET applications will make use of the COM component.
What's the difference between COM interoperability and platform invoke?
COM interoperability allows you to instantiate COM classes within a .NET application and to invoke their members . Platform invoke allows you to call functions from a DLL.
What does the CharSet.Auto parameter in a DllImport attribute specify?
The CharSet.Auto parameter of the DllImport attribute tells the CLR to choose the correct versionANSI or Unicodeof an API for the particular platform on which you are running the code.
Your application uses a COM component stored in a file named ProcessOrders.dll . You deploy the application via xcopy to the test server. Testers report that the orders are not being processed . The test server does have the .NET Framework installed. What could be the problem?
A. RCWs can be installed by xcopy , just like any other .NET assemblies. .NET does not require the Internet to run, nor do RCWs depend on Service Pack 1. When you add RCW to an application, you must make sure that that COM component is registered in the Windows Registry of the target computers. For more information, see the section "Using COM Components" in this chapter.
Your colleague needs to make a call to a COM component named TriState.dll from a serviced component registered as a COM+ server application. You suggest that she use the Type Library Importer tool. What command-line option should you suggest so that the serviced component is capable of accessing the methods of the COM component?
A. The RCWs referenced by serviced components should be strongly named. Therefore, with the given choices, you need to select the /keyfile command-line option of the tlbimp.exe tool. The /keyfile option is passed a filename that contains the public/private key pair to strongly sign an assembly.
You are responsible for migrating an existing COM application to Visual Basic .NET. The existing application consists of eight COM server components and a single client user interface component that instantiates and invokes objects from the server components. You want to give the user interface of the application an overhaul and migrate to Visual Basic .NET with low risk and minimal downtime. How should you proceed?
B. Moving all the code takes longer than moving part of the code, and it introduces additional risk. Because you'd like to rewrite the user interface, you should move that component to .NET before moving the server components.
Your company supplies a COM component to provide advanced data analysis for your clients. Some of your clients are moving to the .NET Framework and require an RCW for your component. How should you proceed?
B. As the vendor of the component, it's your responsibility to supply the PIA.
You wrote a COM component to supply random numbers in a specific distribution to a simple statistical client program. Now you're moving that client program to the .NET Framework. The COM component is used nowhere else, and you have not shipped copies to anyone else. You want to call the objects in the COM server from your new .NET client. How should you proceed?
A. For components you wrote that are used in a single project, the simplest method of creating the RCW is best.
You have written several applications for your own use, all of which share classes from a COM component that you also wrote. You are moving the applications to .NET, but you intend to leave the COM component untouched. How should you proceed?
D. Shared libraries should be placed in the GAC. Code must be signed before it can be placed in the GAC, and only the Type Library Importer tool can sign an RCW.
Your .NET Remoting object needs to use a communications library from a third-party developer. This library is implemented as a COM component. What should you do to continue to use the classes and methods in the communications library?
A. Because you did not write the code for the communications library, the proper way to proceed is to obtain a PIA from the original author.
Your Visual Basic ASP.NET Web service uses functions from a Visual Basic 6 COM library implemented as a DLL via an RCW. You built the RCW by directly referencing the COM DLL. Users are complaining of poor performance. Which of these changes is most likely to improve the performance of your application?
D. Changing from a DLL to an EXE file or from Visual C# .NET to Visual Basic .NET has no significant effect on performance. RCWs are the same no matter how they're created. But rewriting the library into .NET is likely to speed it up because it eliminates the extra calls in the proxy layer.
Your project contains the following API declaration:
<DllImport("kernel32.dll", _ CharSet:=CharSet.Auto)> Public Shared Function GetComputerName(_ ByVal buffer As String, _ size As Integer) As Integer
The project also contains code to use this API to display the computer name:
Public Sub ShowName() Dim buf As String = "" Dim intLen As Integer = 128 Dim intRet As Integer ' Call the Win API method intRet = GetComputerName(buf, intLen) Console.WriteLine(_ "This computer is named " & _ buf.ToString()) End Sub
Users report that no computer name is displayed. What should you do?
C. In the platform invoke calls, you should use StringBuilder instead of String to hold a string buffer that expects to be modified by the function.
You want to use an unmanaged DLL named Balance.dll in your Visual Basic .NET application. Balance.dll does not provide any COM interfaces. How can you call the RetrieveBalance function of this library in your .NET code?
C. Only the PInvoke feature of .NET allows you to call functions from unmanaged DLLs that do not provide any COM interfaces. Therefore, you need to use the DllImport attribute, which tells the .NET Framework where to find the implementation of a method call.
You are using three classes from a COM component in your Visual Basic .NET application. You'd like to give the RCW for the COM component the same version number as the rest of your components when you ship the application. What should you do?
D. Only the Type Library Importer tool can explicitly set the version number for an RCW.
You are planning to use two classes from a COM component in your .NET application. You'd like to place these two classes into a namespace named ComComponents . What must you do?
B. Only the Type Library Importer tool can set the namespace for an RCW.
Your application will use functions from a COM component that uses COM+ services such as object pooling and just-in-time activation. Which of these methods can you use to access the classes in the COM component? (Select the two best answers.)
C and D. You can use COM components that use COM+ services by using the same techniques that you use with COM components.
You have an existing COM component that contains shared classes. These classes encapsulate functionality that you want to use in your .NET application. How can you use these classes while maintaining the benefits of managed code, such as type safety and automatic garbage collection?
D. Only managed code benefits from the features of the CLR. The only way to turn the component into managed code is to rewrite it in .NET.
Your application uses the GetComputerName API function. This function exists in kernel32.dll in both ANSI and Unicode versions. Your declaration is as follows :
<DllImport("kernel32.dll")> _ Public Shared Function GetComputerName(_ buffer As StringBuilder, size As Integer) _ As Integer
Your code is failing with a System.EntryPointNotFoundException exception when you call this function. What should you do to fix this failure?
B. The CharSet.Auto parameter is necessary to tell the CLR to use the ANSI or Unicode versions of the function as appropriate to the operating system.
1. Visual Studio .NET Combined Help Collection, "Interoperating with Unmanaged Code."
2. Adam Nathan. .NET and COM: The Complete Interoperability Guide . Sams, 2002.
3. Andrew Troelsen. COM and .NET Interoperability . Apress, 2002.