Tải bản đầy đủ - 0 (trang)
12-6. Use a COM Component in a .NET Client

12-6. Use a COM Component in a .NET Client

Tải bản đầy đủ - 0trang

CHAPTER 10 ■ UNMANAGED CODE INTEROPERABILITY



You have the following three options for using an RCW:





Obtain an RCW from the author of the original COM component. In this case, the

RCW is created from a PIA provided by the publisher, as Microsoft does for

Microsoft Office.







Generate an RCW using the Tlbimp.exe command-line utility or Visual Studio

.NET.







Create your own RCW using the types in the System.Runtime.InteropServices

namespace. (This can be an extremely tedious and complicated process.)



If you want to use Visual Studio .NET to generate an RCW, you simply need to right-click your

project in Solution Explorer and click Add Reference in the context menu, and then select the

appropriate component from the COM tab. When you click OK, the RCW will be generated and added to

your project references. After that, you can use the Object Browser to inspect the namespaces and

classes that are available.

If you are not using Visual Studio .NET, you can create a wrapper assembly using the Tlbimp.exe

command-line utility that is included with the .NET Framework. The only mandatory piece of

information is the filename that contains the COM component. For example, the following statement

creates an RCW with the default filename and namespace, assuming that the MyCOMComponent.dll file is

in the current directory.

tlbimp MyCOMComponent.dll

Assuming that MyCOMComponent has a type library named MyClasses, the generated RCW file will have

the name MyClasses.dll and will expose its classes through a namespace named MyClasses. You can also

configure these options with command-line parameters, as described in the MSDN reference. For

example, you can use /out:[Filename] to specify a different assembly file name and

/namespace:[Namespace] to set a different namespace for the generated classes. You can also specify a

key file using /keyfile[keyfilename] so that the component will be signed and given a strong name,

allowing it to be placed in the Global Assembly Cache (GAC). Use the /primary parameter to create a PIA.

If possible, you should always use a PIA instead of generating your own RCW. PIAs are more likely to

work as expected, because they are created by the original component publisher. They might also

include additional .NET refinements or enhancements. If a PIA is registered on your system for a COM

component, Visual Studio .NET will automatically use that PIA when you add a reference to the COM

component. For example, the .NET Framework includes an adodb.dll assembly that allows you to use

the ADO classic COM objects. If you add a reference to the Microsoft ActiveX Data Objects component,

this PIA will be used automatically; no new RCW will be generated. Similarly, Microsoft Office provides a

PIA that improves .NET support for Office automation. However, you must download this assembly from

the MSDN web site.



The Code

The following example shows how you can use COM Interop, in the form of the Microsoft Office PIAs, to

access Office automation functionality from a .NET Framework application. As you can see, the code is

like any other .NET code—the key is the need to add the appropriate reference to the COM wrapper,

which handles the communication between your code and the COM component. The example code also

highlights (using the Workbooks.Open method) the significant syntax simplification enabled by .NET 4.0

when calling Interop methods that contain many optional parameters—something discussed further in

recipe 12-8.



611



www.it-ebooks.info



CHAPTER 12 ■ UNMANAGED CODE INTEROPERABILITY



using

using

using

using



System;

System.IO;

System.Runtime.InteropServices;

Excel = Microsoft.Office.Interop.Excel;



namespace Apress.VisualCSharpRecipes.Chapter12

{

class Recipe12_06

{

static void Main()

{

string fileName =

Path.Combine(Directory.GetCurrentDirectory(),

"Ranges.xlsx");

// Create an instance of Excel.

Console.WriteLine("Creating Excel instance...");

Console.WriteLine(Environment.NewLine);

Excel.Application excel = new Excel.Application();

// Open the required file in Excel.

Console.WriteLine("Opening file: {0}", fileName);

Console.WriteLine(Environment.NewLine);

// Open the specified file in Excel using .NET 4.0 optional

// and named argument capabilities.

Excel.Workbook workbook =

excel.Workbooks.Open(fileName, ReadOnly: true);

/* Pre-.NET 4.0 syntax required to open Excel file:

Excel.Workbook workbook =

excel.Workbooks.Open(fileName, Type.Missing,

false, Type.Missing, Type.Missing, Type.Missing,

Type.Missing, Type.Missing, Type.Missing, Type.Missing,

Type.Missing, Type.Missing, Type.Missing, Type.Missing,

Type.Missing); */

// Display the list of named ranges from the file.

Console.WriteLine("Named ranges:");

foreach (Excel.Name name in workbook.Names)

{

Console.WriteLine(" {0} ({1})",name.Name,name.Value);

}

Console.WriteLine(Environment.NewLine);

// Close the workbook.

workbook.Close();

/* Pre-.NET 4.0 syntax required to close Excel file:

workbook.Close(Type.Missing, Type.Missing, Type.Missing); */



612



www.it-ebooks.info



CHAPTER 10 ■ UNMANAGED CODE INTEROPERABILITY



// Terminate Excel instance.

Console.WriteLine("Closing Excel instance...");

excel.Quit();

Marshal.ReleaseComObject(excel);

excel = null;

// Wait to continue.

Console.WriteLine(Environment.NewLine);

Console.WriteLine("Main method complete. Press Enter.");

Console.ReadLine();

}

}}



12-7. Release a COM Component Quickly

Problem

You need to ensure that a COM component is removed from memory immediately, without waiting for

garbage collection to take place, or you need to make sure that COM objects are released in a specific

order.



Solution

Release the reference to the underlying COM object using the static Marshal.FinalReleaseComObject

method and passing the appropriate RCW.



How It Works

COM uses reference counting to determine when objects should be released. When you use an RCW, the

reference will be held to the underlying COM object even when the object variable goes out of scope.

The reference will be released only when the garbage collector disposes of the RCW object. As a result,

you cannot control when or in what order COM objects will be released from memory.

To get around this limitation, you usually use the Marshal.ReleaseComObject method. However, if

the COM object’s pointer is marshaled several times, you need to repeatedly call this method to decrease

the count to zero. However, the FinalReleaseComObject method allows you to release all references in

one go, by setting the reference count of the supplied RCW to zero. This means that you do not need to

loop and invoke ReleaseComObject to completely release an RCW.

For example, in the Excel example in recipe 12-6, you could release all references to the Excel

Application component using this code:

System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excel);



613



www.it-ebooks.info



CHAPTER 12 ■ UNMANAGED CODE INTEROPERABILITY



■ Note The ReleaseComObject method does not actually release the COM object; it just decrements the

reference count. If the reference count reaches zero, the COM object will be released. FinalReleaseComObject

works by setting the reference count of an RCW to zero. It thus bypasses the internal count logic and releases all

references.



12-8. Use Optional Parameters

Problem

You need to call a method in a COM component without supplying all the required parameters.



Solution

Prior to .NET 4.0, you would need to use the Type.Missing field. As of .NET 4.0, you can simply omit

unused optional parameters and use named parameters for those values you do want to provide.



How It Works

The .NET Framework is designed with a heavy use of method overloading. Many methods are

overloaded several times so that you can call the version that requires only the parameters you choose to

supply. COM, on the other hand, does not support method overloading. Instead, COM components

usually implement methods with a long list of optional parameters.

Prior to .NET 4.0, C# (unlike Visual Basic .NET) did not support optional parameters, which meant

C# developers were forced to supply numerous additional or irrelevant values when calling a method on

a COM component. And because COM parameters are often passed by reference, code could not simply

pass a null reference. Instead, it had to declare an object variable and then pass that variable. This

resulted in code that used the Type.Missing field whenever there was an unused optional parameter. In

Office automation code, it is not unusual to see method calls with 10 or 15 Type.Missing parameters with

1 or 2 real values scattered among them. The optional and named parameter features included in .NET

mean that COM Interop code becomes much cleaner and easier to understand. Instead of providing

Type.Missing references for optional parameters you do not use, you can simply ignore them. And for

those few parameters that you do need to provide, you can use named parameter syntax.



The Code

The following code snippet, taken from recipe 12-6, illustrates the improved clarity achieved using the

optional and named parameter support added in .NET 4.0. In the example, the fileName parameter is

not named as it is in the correct position (first), whereas ReadOnly would actually be the third parameter

if it were not identified by name.



614



www.it-ebooks.info



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

12-6. Use a COM Component in a .NET Client

Tải bản đầy đủ ngay(0 tr)

×