通过 COM 互操作在 .NET 中访问 ADO 数据






4.83/5 (18投票s)
2002年3月26日
7分钟阅读

203061

1730
本文介绍了如何在 .NET 中使用 COM 对象。
这是我提交给 CodeProject 的第一篇文章。我一直想为 CodeProject 提交文章,但由于各种原因未能如愿。现在,我设法发布了这篇文章。希望大家喜欢它的程度和我写它一样。
引言
本文介绍了如何从 .NET 访问传统的 COM 对象。
为了演示互操作,我们将首先介绍如何显示通过 Ole Db Service Component 作为 COM 对象公开的 DataLink 属性对话框。
我们还将介绍如何从 .NET 访问传统的 ADO 组件。
在 .NET 中,访问数据的首选方式是通过 ADO.NET。但是,如果您想出于某种原因使用 ADO,本文将介绍如何实现。一个可能的场景是,您想重用现有的 COM 组件,这些组件返回 ADO 记录集。
本文不详细介绍实际的互操作是如何发生的,即内部机制。这需要对 COM 及其相关复杂性有深入的了解。.NET 以 CCW 和 RCW 的形式增加了自己的抽象/访问机制,以实现互操作。
本文使用 C# 作为实现语言。但是,在 Visual Basic.NET 中执行相同的操作也非常简单。此外,本文要求您安装 Visual Studio .NET。 .NET 通过互操作层提供了访问 COM 组件的功能。
要了解更多关于 .NET 中的 COM 互操作,您可以阅读这篇来自 https://codeproject.org.cn/dotnet/cominterop.asp 的精彩文章。
调用 DataLink 属性对话框
以下是调用 DataLink 属性对话框所需的步骤。
为了调用 Datalink 属性对话框,您需要将 COM CoClasses 和 COM 中的数据结构转换为 .NET 框架可以理解的内容。这通常是一组类和结构。有关更多信息,您可以参考 MSDN 中的 InteropServices 命名空间文档。
如果您使用的是 Visual Studio .NET,这个过程非常简单。您只需执行以下步骤。
- 创建一个新项目,选择 **Visual C#** 项目,然后在模板部分选择 **Windows 应用程序**。给它一个有意义的名称,比如 DataLink。
- 点击 OK 将生成一个带有窗体的 Windows 应用程序。
- 在此之后,我们需要引用 COM 组件,为该组件生成程序集/类包装器。如果您使用过 VC++,这个过程与为 COM 对象生成类包装器非常相似。然而,在 .NET 中,这只是一个互操作程序集(一个 dll)和一个命名空间。
- 在 **解决方案资源管理器** 中右键单击 **引用** 部分,然后单击 **添加引用**。
- 这将打开以下对话框。转到 COM 选项卡。
在我们继续之前,我们需要知道公开 DataLink 属性对话框的 COM 对象。这个 COM 对象存在于 oledb32.dll 中,通常位于 \Program Files\Common Files\System\OLE DB\oledb32.dll 路径下。
您可以通过在此对话框中搜索以下条目来找到此信息,
Microsoft OLE DB Service Component 1.0 Type Library.
选择条目后,通过单击“选择”按钮将其添加。由于我们还想通过传统的 ADO 进行数据访问,因此我们需要为其生成互操作程序集。因此,我们选择 **Microsoft ActiveX Data Objects 2.5 Library**。添加引用后,Visual Studio .NET 会自动为其生成互操作程序集包装器,并在项目 bin\debug(或 release)目录中创建 dll。
默认情况下,ADO 包装器 dll 在 debug(或 release)目录中是看不到的,但是如果您将程序集引用的“复制本地”属性更改为“true”,您应该能够在项目的 debug(或 release)目录中看到 dll。通过转到项目菜单并选择 **显示所有文件** 选项,您可以查看 dll 的物理存在。这将允许您查看项目目录中存在的所有文件。
现在我们已经为 COM 对象生成了类/程序集,现在我们可以开始使用它们了。
第一步是包含以下命名空间
using System.Runtime.InteropServices; using MSDASC; using ADODB;
InteropServices
命名空间包含访问 COM 对象所需的服务的。通过 Visual Studio .NET 生成的 MSDASC
命名空间包含访问 DataLink
组件的类和方法。ADODB
命名空间顾名思义,包含了从 .NET 访问 ADO 的类。DataLinksClass objDataLink=new DataLinksClass();
objDataLink.hWnd = this.Handle.ToInt32();
Connection obj = (Connection) objDataLink.PromptNew();
首先,我们通过创建 DataLinksClass
的实例来创建一个 DataLink
对象。
请注意,在上面的代码中,hWnd
参数需要一个整数形式的父窗口句柄。当前窗口窗体的句柄通过 this.Handle
访问,它返回一个 Systems.IntPtr
,我们通过调用 ToInt32
函数将其转换为整数。
PromptNew
函数会显示 DataLink
属性对话框,如下所示,并返回一个 ADO 连接对象。由于我们为 ADO 生成了类包装器,因此我们可以直接使用连接类,通过类型转换将返回值转换为 ADO 连接对象。
ADO 连接对象的 ConnectionString
属性现在包含了 DataLink 属性对话框返回的 ConnectionString
。
现在我们获得了连接字符串,是时候使用它来连接数据库了。使用 Connection
对象,我们现在可以打开连接。
Connection objConn = (Connection) objDataLink.PromptNew();
objConn.Open(objConn.ConnectionString, null,null,
(int)ConnectModeEnum.adModeUnknown);
Object RecordsAffected = null;
// We assume that Northwind Access DB is selected in the DataLink
// Property dialog
Recordset objRecordset = objConn.Execute("select * from products",
out RecordsAffected,
(int) CommandTypeEnum.adCmdText);
注意,在 ADO 中,Connection 对象的 Open 方法允许可选参数,因此可以不带任何参数调用该方法。但是,在 Visual Studio .NET 生成的类中,它需要所有参数。我相信应该有一个选项可以生成支持可选参数的程序集/包装器,如果有人知道如何做到这一点,请给我发邮件,以便我更新本文。因此,Open 方法现在具有以下语法。
Void Open(string ConnectionString,string UserID,string Password,int Options)
我们知道 ConnectionString,对于其余参数 UserID 和 Password,我们传递空字符串作为参数,因为我们使用的是 MS-Access 数据库。但是,根据您连接的数据库,您可能需要为这些参数提供值。最后一个参数 Options 指定一个整数值,帮助 ADO 提供者评估如何处理命令类型。现在我们可以传递 adModeUnknown
作为参数。我们通过类型转换简单地将枚举转换为整数。现在连接已打开,我们可以通过此连接执行查询,从而获取 ADO Recordset。
为此,我们调用 Connection 对象的 execute 方法,该方法具有以下语法
Recordset Execute(string CommandText,out object RecordsAffected,int Options)
CommandText
代表返回记录集的查询。第二个参数很有趣,我们传递一个对象。RecordsAffected 参数提供有关操作影响了多少条记录的信息。请注意,它不返回已执行查询的记录数,而是返回执行查询所影响的记录数。我们指定 out
关键字是因为函数承诺在该参数上返回值,即 RecordsAffected
在 Execute
语句完成后将包含一些信息。
由于我们对此值不感兴趣,因此我们传递一个初始化为 null 的对象,并在 Options 中指定枚举,表示它是具有枚举值 'adCmdText
' 的命令文本。
现在我们已经执行完毕,记录集已返回,我们将使用 DataGrid
控件以网格格式显示记录集。为此,第一步是创建一个 DataSet
实例。
DataSet objDS = new DataSet();
之后,我们创建一个 OleDbDataAdapter
对象,OleDbDataAdapter objProducts = new OleDbDataAdapter();
然后我们使用 OleDbDataAdapter
中的 Fill 函数的以下重载来填充 DataAdapter,public int Fill(DataSet dataSet,object ADODBRecordSet,string srcTable);
如您在上面的函数 Fill 中看到的,它接受 ADO 记录集作为其参数之一。显然,不用说,redmontanians 已经仔细考虑过提供对 ADO 记录集的直接支持。所以我们的调用变成,objProducts.Fill(objDS,objRecordset,"products");
现在我们已经填充了数据适配器,是时候将此信息传递给 Grid 以显示结果了。Datagrid 控件有一个名为 DataSource
的属性,我们将其初始化如下dataGrid1.DataSource=objDS.DefaultViewManager;
现在您可以在网格中看到显示的结果。