域名频道-专业提供域名注册,网站空间,电子邮箱,VPS主机等服务
首页 域名注册 虚拟主机 香港主机 美国主机 VPS主机 网站建设 ShopEX网店 软件开发 客户中心 购物车
域名服务,域名注册 常见问题
文章搜索


本类TOP10
·松江网页设计_松江网页制...
·上海轨道交通图-上海地图
·松江公交线路图-松江地图
·marquee连续滚动
·今天几度?-天气预报-全...
·松江新城地图-松江地图
·松江城区地图-松江地图
·HAO123邮箱登陆代码
·shopex免费模板,下...
·松江DNS服务器地址,松...
当前位置:域名频道首页 > 常见问题 > 网页制作
C# 程序员参考--COM Interop 第一部分:C# 客户端教程

COM Interop 提供对现有 COM 组件的访问,而不需要修改原始组件。若要将 COM 代码合并到 托管应用程序,请通过使用 COM Interop 实用工具 (TlbImp.exe) 导入相关的 COM 类型。一经导入 ,COM 类型就可以使用。

此外,COM In terop 还使 COM 开发人员能够像访问其他 COM 对 象一样轻松访问托管对象。同样,COM Interop 提供了 一个专用实用工具 (RegAsm.exe),此工具将托管类型 导出到类型库中,并将托管组件注册为传统 COM 组件。

在运行时,公共语言运行库根据需要在 COM 对象和 托管对象之间封送数据。

该教程显示如何使用 C # 与 COM 对象交互操作。

COM Int erop 第二部分:C# 服务器教程讲述如何将 C# 服务器 与 C++ COM 客户端一起使用。有关两个教程的概述,请参 见 COM Interop 教程。

教程

C# 使用 .NET Framework 功能执行 COM Interop。C# 支持:


创建 COM 对象。

确定 COM 接口 是否由对象实现。

调用 COM 接口上的方法 。

实现可由 COM 客户端调用的对象和接口 。


.NET Framework 使用 COM Interop 处理引用计数问题,因此不必调用或实 现 AddRef 和 Release。

本教程 阐述以下主题:


创建 COM 类包装

声明 COM coclass

创建 COM 对象

声明 COM 接口< br>
使用转换而不是 QueryInterface

综述


创建 COM 类包装

要使 C# 代码引用 COM 对象和接 口,需要在 C# 内部版本中包含 COM 接口的 .NET Framework 定义。完成此操作的最简单方法是使用 Tl bImp.exe(类型库导入程序),它是一个包括在 .NET Framework SDK 中的命令行工具。TlbImp 将 COM 类型库转换为 .NET Framework 元数 据,从而有效地创建一个可以从任何托管语言调用的托管包装。用 TlbImp 创建的 .NET Framework 元数据可 以通过 /R 编译器选项包括在 C# 内部版本中。如果使用 Visual Studio 开发环境,则只需添加对 COM 类型库的引用,将为您自动完成此转换。

TlbI mp 执行下列转换:


COM coc lass 转换为具有无参数构造函数的 C# 类。
COM 结构转换为具有公共字段的 C# 结构。


检查 TlbImp 输出的一种很好的方法是运 行 .NET Framework SDK 命令行工具 Ild asm.exe(Microsoft 中间语言反汇编程序)来查 看转换结果。

虽然 TlbImp 是将 COM 定义转换为 C# 的首选方法,但也不是任何时候都可以使用它 (例如,在没有 COM 定义的类型库时或者 TlbImp 无 法处理类型库中的定义时,就不能使用该方法)。在这些情况下,另 一种方法是使用 C# 属性在 C# 源代码中手动定义 COM 定义。创建 C# 源映射后,只需编译 C# 源代码就可产生 托管包装。

执行 COM 映射需要理解的主要属 性包括:


ComImport,它将类 标记为在外部实现的 COM 类。

Guid, 它用于为类或接口指定通用唯一标识符 (UUID)。
< br> InterfaceType,它指定接口是从 IUnk nown 还是从 IDispatch 派生。

PreserveSig,它指定是否应将本机返回值从 HRE SULT 转换为 .NET Framework 异常。


这些属性中的每一个都在本教程的某个实际示例 的上下文中进行了显示。

声明 COM cocl ass

COM coclass 在 C# 中表 示为类。这些类必须具有与其关联的 ComImport 属性。 下列限制适用于这些类:


类不能从任何 其他类继承。

类不能实现任何接口。
< br> 类还必须具有为其设置全局唯一标识符 (GUID) 的 Guid 属性。


以下示例在 C# 中声明一个 coclass:

//
/ / declare FilgraphManager as a COM coclass
//
[ComIm port, Guid("E436EBB3-524F-11CE -9F53-0020AF0BA770")]
clas s FilgraphManager
{
}
C# 编译器将添加一个无参数构造函数,可以调用此 构造函数来创建 COM coclass 的实例。
创建 COM 对象

COM coclass 在 C# 中表示为具有无参数构造函数的类。使用 new 运 算符创建该类的实例等效于在 C# 中调用 CoCreateI nstance。使用以上定义的类,就可以很容易地实例化此类:

class MainClass
{< br> public static void Main ()
{
//
// Create an instance of a COM coclass - calls
//
// CoCrea teInstance(E436EBB3-524F-11CE- 9F53-0020AF0BA770,
// NULL, CLS CTX_ALL,
// IID_IUnknown, &
f)
//
/ / returns null on failure.
//
Filgra phManager f = new FilgraphMana ger();

}
}

声 明 COM 接口

COM 接口在 C# 中表示 为具有 ComImport 和 Guid 属性的接口。它不能 在其基接口列表中包含任何接口,而且必须按照方法在 COM 接 口中出现的顺序声明接口成员函数。

在 C# 中 声明的 COM 接口必须包含其基接口的所有成员的声明,IUn known 和 IDispatch 的成员除外(.NET F ramework 将自动添加这些成员)。从 IDispatc h 派生的 COM 接口必须用 InterfaceType 属性予以标记。

从 C# 代码调用 COM 接 口方法时,公共语言运行库必须封送与 COM 对象之间传递的参 数和返回值。对于每个 .NET Framework 类型均有 一个默认类型,公共语言运行库将使用此默认类型在 COM 调用 间进行封送处理时封送。例如,C# 字符串值的默认封送处理是封 送到本机类型 LPTSTR(指向 TCHAR 字符缓冲区的指 针)。可以在 COM 接口的 C# 声明中使用 Marsha lAs 属性重写默认封送处理。

在 COM 中 ,返回成功或失败的常用方法是返回一个 HRESULT,并在 MIDL 中有一个标记为“retval”、用于方法的实际返回 值的 out 参数。在 C#(和 .NET Framewor k)中,指示已经发生错误的标准方法是引发异常。

默认情况下,.NET Framework 为由其调用的 C OM 接口方法在两种异常处理类型之间提供自动映射。
< br>
返回值更改为标记为 retval 的参数的签 名(如果方法没有标记为 retval 的参数,则为 void )。

标记为 retval 的参数从方法的参 数列表中剥离。


任何非成功返回值都将导 致引发 System.COMException 异常。

此示例显示用 MIDL 声明的 COM 接口以及用 C# 声明的同一接口(注意这些方法使用 COM 错误处理方 法)。

下面是该接口的原始 MIDL 版本:< br>
[
odl,
uuid (56A868B1-0AD4-11CE-B03A-0020A F0BA770),
helpstring("IM ediaControl interface"),
dual,
oleautomation
]
interface IMediaControl : IDispatch
{
[id(0 x60020000)]
HRESULT Run( );


[id(0x60020001)]
HRESULT Pause();


[id(0x60020002)]
HRES ULT Stop();


[id(0x60 020003)]
HRESULT GetStat e( [in] long msTimeout, [out] long* pfs);


[id(0x60 020004)]
HRESULT RenderF ile([in] BSTR strFilename);

[id(0x60020005)]
HRESULT AddSourceFilter( [in] BSTR strFilename, [out] IDisp atch** ppUnk);


[id(0x 60020006), propget]
HRES ULT FilterCollection([out, ret val] IDispatch** ppUnk);

< br> [id(0x60020007), propget]
HRESULT RegFilterCollec tion([out, retval] IDispatch** ppUnk);


[id(0x60020 008)]
HRESULT StopWhenRe ady();

};


下面是该接口的 C # 等效版本:

using System.Ru ntime.InteropServices;


// Declare IMediaControl as a COM interface which
// der ives from the IDispatch interf ace.
[Guid("56A868B1-0AD4- 11CE-B03A-0020AF0BA770"),
InterfaceType(ComInterfaceT ype.InterfaceIsDual)]
inte rface IMediaControl // cannot list any base interfaces here
{
// Note that the members of IUnknown and Inter face are NOT
// listed here
//
void Ru n();


void Pause();
< br>
void Stop();


void GetState( [In] i nt msTimeout, [Out] out int pf s);


void RenderFile (
[In, MarshalAs(Unmana gedType.BStr)] string strFilen ame);


void AddSourc eFilter(
[In, MarshalAs (UnmanagedType.BStr)] string s trFilename,
[Out, Mars halAs(UnmanagedType.Interface) ] out object ppUnk);


[return : MarshalAs(Unmanage dType.Interface)]
objec t FilterCollection();


[return : MarshalAs(Unmanag edType.Interface)]
obje ct RegFilterCollection();


void StopWhenReady( );

}

请注意,C# 接口是如何映射 错误处理情况的。如果 COM 方法返回错误,则 C# 一方将 引发异常。

若要防止 HRESULT 翻译为 COMException,请在 C# 声明中将 Preser veSig(true) 属性附加到方法。有关详细信息,请参见 PreserveSigAttribute 类。
使用转换而不是 QueryInterface
只有在可以访问 C# coclass 实现的接口时,C# coclass 才会非常有用。在 C++ 中,可以使用 I Unknown 接口上的 QueryInterface 方法 定位对象接口。在 C# 中,通过将 COM 对象显式转换为所 需的 COM 接口,可以做到这一点。如果转换失败,则引发无效 转换异常:

// Create an inst ance of a COM coclass:
Filg raphManager graphManager = new FilgraphManager();


// See if it supports the IMediaC ontrol COM interface.
// N ote that this will throw a Sys tem.InvalidCastException if // the cast fails. This is e quivalent to QueryInterface fo r
// COM objects:
IMedi aControl mc = (IMediaControl) graphManager;


// Now yo u call a method on a COM inter face:
mc.Run();


综述< br>
下面是一个使用 C# 创建 AVI 文件查看器 的完整示例。此程序创建 COM coclass 的实例,将其 转换为 COM 接口,然后调用 COM 接口上的方法。

本节中的示例代表两种方法:


示例 1 使用 TlbImp 创建 .NET Fram ework 类。

示例 2 编写手动执行 COM 映射的 C# 代码。


示例 1:使用 TlbImp

本例显示如何使用 Tl bImp 创建 AVI 查看器。程序从命令行读取 AVI 文 件名,创建 Quartz COM 对象的实例,然后使用 Re nderFile 和 Run 方法显示 AVI 文件。

以下是生成该程序的步骤:


在 TLB 上运行 TlbImp。本示例使用的媒体播放机包含 在应位于 Windows 系统目录中的 Quartz.dll 中。使用以下命令创建 .NET Framework DLL :
tlbimp c:\winnt\system32\ quartz.dll /out:QuartzTypeLib. dll

请注意,得到的 DLL 需要命名为 QuartzTypeLib,以便 .NET Framewor k 可以在运行时正确加载包含类型。


可以使用 Ildasm 工具查看得到的 DLL。例如,若要显 示 QuartzTypeLib.dll 文件的内容,请使用以 下命令:
Ildasm QuartzTypeLib.d ll


生成程序时使用 C# 编译器选 项 /R 以包含 QuartzTypeLib.dll 文件。


然后就可以使用此程序显示影片(用于测 试的一个影片示例是驻留在 Windows 目录中的 Cloc k.avi)。

// interop1.cs< br>// compile with: /R:QuartzT ypeLib.dll
using System;

class MainClass
{
/************************** ****************************** ****
Abstract: This method collects the file name of an AVI to
show th en creates an instance of the Quartz COM object.
To show the AVI, the program cal ls RenderFile and Run on
IMediaControl. Quartz use s its own thread and window to
display the AVI.The main thread blocks on a ReadL ine until
the user p resses ENTER.
I nput Parameters: the location of the AVI file it is
going to display
Returns: void
*************************** ****************************** *****/
public static void Main(string[] args)
{
// Che ck to see if the user passed i n a filename
i f (args.Length != 1)
{
DisplayUsage();

return;

}

if (arg s[0] == "/?")
{
Display Usage();

return;

}

string filenam e = args[0];


// Check to see if the fil e exists
if (!S ystem.IO.File.Exists(filename) )
{
Console.WriteLine("F ile " + filename + " not found .");

Disp layUsage();

return;

}

// Create instance of Quartz
// (Calls CoCreateInstanc e(E436EBB3-524F-11CE-9F53-0020 AF0BA770,
// NU LL, CLSCTX_ALL, IID_IUnknown, &
graphManager).):

try
{
Quart zTypeLib.FilgraphManager graph Manager =
new QuartzTypeLib.Filg raphManager();


// QueryInterface f or the IMediaControl interface :
QuartzT ypeLib.IMediaControl mc =
(Quartz TypeLib.IMediaControl)graphMan ager;


// Call some methods on a CO M interface
// Pass in file to RenderF ile method on COM object.
mc.RenderFil e(filename);


// Show file.
mc.Run();

}
cat ch(Exception ex)
{
Conso le.WriteLine("Unexpected COM e xception: " + ex.Message);

}

// Wait for completion.
Console.WriteLine ("Press Enter to continue.");

Console.ReadLi ne();

}

private static void Displa yUsage()
{
// User did not provide enough parameters.
// Display usage:
Console.WriteLine("V ideoPlayer: Plays AVI files.") ;

Console.Writ eLine("Usage: VIDEOPLAYER.EXE filename");

Co nsole.WriteLine("where filenam e is the full path and");

Console.WriteLine( "file name of the AVI to displ ay.");

}
}
运行示例

若要显示影片示例 Clock.a vi,请使用以下命令:

interop1 %w indir%\clock.avi

当您按 EN TER 键后,屏幕上将显示影片。

示例 2:C # 代码方法

本示例使用与示例 1 相同的 M ain 方法,但它只是使用 C# 映射媒体播放机 COM 对 象,而不是运行 TlbImp。

// inte rop2.cs
using System;

us ing System.Runtime.InteropServ ices;


namespace Quartz TypeLib
{
// Decl are IMediaControl as a COM int erface which
// deri ves from IDispatch interface:< br> [Guid("56A868B1-0AD4- 11CE-B03A-0020AF0BA770"),
InterfaceType(ComInterfa ceType.InterfaceIsDual)]
interface IMediaControl // Cannot list any base inter faces here
{
// Note that IUnknown Interface members are NOT lis ted here:


void Run();

void Pause();


void Stop();


void GetState( [In] i nt msTimeout, [Out] out int pf s);


void R enderFile(
[In, MarshalAs(UnmanagedType .BStr)] string strFilename);

void AddSou rceFilter(
[In, MarshalAs(UnmanagedTyp e.BStr)] string strFilename, < br> [Out, Mar shalAs(UnmanagedType.Interface )]
out ob ject ppUnk);


[return: MarshalAs(Unmanage dType.Interface)]
object FilterCollection();


[return: MarshalAs(UnmanagedType.Interf ace)]
object R egFilterCollection();


void St opWhenReady();

}
// Declare FilgraphManag er as a COM coclass:
[ComImport, Guid("E436EBB3-524 F-11CE-9F53-0020AF0BA770")] class FilgraphManager // Cannot have a base class or
// interface list here.
{
// Cannot have any me mbers here
// NOTE that the C# compiler will add a default constructor
// for you (no par ameters).
}
}

class MainClass
{
/*********************** ****************************** *****
Abstract: This method collects the file name of an AVI to
show t hen creates an instance of the Quartz COM object.
T o show the AVI, the program ca lls RenderFile and Run on
IMediaControl. Quartz us es its own thread and window t o
display the AVI.Th e main thread blocks on a Read Line until
the user presses ENTER.
Input Parameters: the location of the AVI file it is
going to display
Returns: void
************************** ****************************** *****/

public s tatic void Main(string[] args)
{
/ / Check to see if the user pas sed in a filename:
if (args.Length != 1)
{
DisplayUsage();

return;

}

i f (args[0] == "/?")
{
DisplayUsage();

return;

}

String filename = args[0];


// Check to see if the file exists
if (!System.IO.File.Exists(fi lename))
{
Console.Write Line("File " + filename + " no t found.");

DisplayUsage();

return;

}

// Cr eate instance of Quartz
// (Calls CoCreateIn stance(E436EBB3-524F-11CE-9F53 -0020AF0BA770,
// NULL, CLSCTX_ALL, IID_IUn known,
// &am p;
graphManager).):
try
{
QuartzTypeLib. FilgraphManager graphManager =
ne w QuartzTypeLib.FilgraphManage r();


// QueryInterface for the IMe diaControl interface:
QuartzTypeLib.IMe diaControl mc =
(QuartzTypeLib.I MediaControl)graphManager;


// Call some methods on a COM interfa ce.
// Pa ss in file to RenderFile metho d on COM object.
mc.RenderFile(filename );


// Show file.
mc.Run();

}
catch( Exception ex)
{
Console. WriteLine("Unexpected COM exce ption: " + ex.Message);

}
// W ait for completion.
Console.WriteLine("Press Enter to continue.");

Console.ReadLine();
}

privat e static void DisplayUsage() < br> {
// User did not provide enough pa rameters.
// D isplay usage.
Console.WriteLine("VideoPlayer : Plays AVI files.");

Console.WriteLine("Usa ge: VIDEOPLAYER.EXE filename") ;

Console.Writ eLine("where filename is the f ull path and");

Console.WriteLine("file name of the AVI to display.");

}
}

运行示例
< br>若要显示影片示例 Clock.avi,请使用以下命令:

interop2 %windir%\cloc k.avi

当您按 ENTER 键后,屏幕上将 显示影片。

< br>

来自:域名频道 时间:2006-9-19 返回 常见问题 首页
关于我们 联系方式 付款事宜 招聘启事 网站地图 域名注册 虚拟主机 法律顾问

Copyright 2000-2013 域名频道(www.DNS110.com)
地址:上海市松江区新松江路1188弄37号 邮编:201620
电话:021-67820741 67820742 67820743 传真:转分机805 值班电话:021-67820743
QQ:219854 Email:support@dns110.com