用C#创建COM对象
在本篇文章中,我们将讨论下面的问题:4_Lq#s2Z'D)^4p+Qc&IP0_Q
·使用C#创建一个简单的COM对象(使用COM的Interop特性)。B7E8U g^.W|}+m+G
·从VC++客户端软件中访问COM。客户端软件使用了TypeLibrary(.TLB文件)。为了简单和方便开发人员使用、测试起见,我们使用了SQLSERVER数据库软件的缺省安装中的Northwind数据库。W0o-tJy1z8d'h
K"ua }w5PX
·修改COM对象中SQLServer的名字,与SQLServer连接。 ,|UZ3Q y
·我们已经创建了连接数据库用的分别为scott、tiger的用户名和口令,我们可以使用它或者其他现有的用户名和口令。8dmf8NKAQ
第一部分:用C#创建简单的COM对象
COM对象是ClassLibrary类,它生成DLL文件。要在VS开发环境中创建一个简单的COM对象,我们可以依次选择“文件”->“新创建”->“工程”->“VisualC#工程”->“类库”,然后创建一个名字为Database_COMObject的工程。 |atA\;}WT
}-dgN(V'wf
需要注意的是:在COM中调用VC#对象需要下面的条件:
·类必须是public性质。 )^0cU8eZ
·特性、方法和事件必须是public性质的。
svn)Sr?*Y/}p
·特性和方法必须在类接口中定义。
·事件必须在事件接口中定义。
不是在这些接口中定义的public性质的类成员不能被COM访问,但它们可以被其他的.NET Framework对象访问。要让COM能够访问特性和方法,我们必须在类接口中定义它们,使它们具有DispId属性,并在类中实现这些特性和方法。这些成员定义时的顺序也就是它们在COM中顺序。要让COM访问类中的事件,必须在事件接口中定义这些事件,并赋予它们DispId属性。事件接口不应当由类完成,类只实现类接口(它可以实现不止一个接口,但第一个接口是缺省接口),应当在缺省接口中实现需要让COM访问的方法和特性,方法和特性必须被标识为public性质,并符合在类接口中的定义。需要让COM访问的事件也在缺省的类接口中完成,它们也必须被标识为public性质,并符合事件接口中的定义。
在接口名字之前,每个接口需要一个GUID特性。要生成变个唯一的Guid,需要运行guidgen.exe工具软件,并选择“注册表格式”。,{9Q.c`#@InQT
下面是一个类界面:
VNIu.Q
[Guid("694C1820-04B6-4988-928F-FD858B95C880")] 8G3\X*W YD9B
public interface DBCOM_Interface
{
[DispId(1)]
void Init(string userid , string password);
[DispId(2)]
bool ExecuteSelectCommand(string selCommand); w\|qI`
[DispId(3)]
bool NextRow();
[DispId(4)]
void ExecuteNonSelectCommand(string insCommand); `,m'SXo2t
[DispId(5)] 4w T4`@K6G
string GetColumnData(int pos);
} 0P8m;RH'G:nh
VWw/f-N0ej
dL"m@c.jdbgF,V
COM事件接口:
// 事件接口Database_COMObjectEvents
[Guid("47C976E0-C208-4740-AC42-41212D3C34F0"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] $];j0H-HA*O2k0~F
public interface DBCOM_Events
{
} (lp_E#__~"}%N#WN
b_Hv SKU ]3T
下面是实际的类定义:
[Guid("9E5E5FB2-219D-4ee7-AB27-E4DBED8E123E"),
ClassInterface(ClassInterfaceType.None), 6p$O ez)r6F/q,p
ComSourceInterfaces(typeof(DBCOM_Events))]
public class DBCOM_Class : DBCOM_Interface
{ Ch os.IeS8z2J
Baq.X.G[
需要注意的是,在类的前面,需要设置下面的特性:
d W(P@w+t
ClassInterface(ClassInterfaceType.None), *T'uH\YHF%s+p-f
ComSourceInterfaces(typeof(DBCOM_Events))] &nC;a4sZ5C
ClassInterfaceType.None表示没有为该类生成类接口,如果没有明确地实现接口,类只能通过IDispatch提供后期绑定访问。用户希望通过明确地由类实现的接口使外部对象能够访问类的功能,这也是推荐的ClassInterfaceAttribute的设置。
ComSourceInterfaces(typeof(DBCOM_Events))]确定许多作为COM事件向外部对象提供的接口。在本文的例子中,我们不对外部对象开放任何事件。 1?;KXY |Zf%[^
下面是COM对象完整的源代码:
:B%T~nF,zGA
using System; 6J$iM"J*x3d'V#e*~
using System.Runtime.InteropServices;
using System.IO;
using System.Text; ?-KI tU{["T@
using System.Data.SqlClient; EV a/h%iOB\
using System.Windows.Forms ;
namespace Database_COMObject
{ LbqC,I
[Guid("694C1820-04B6-4988-928F-FD858B95C880")]
public interface DBCOM_Interface v.}rnIoW
{
[DispId(1)]
void Init(string userid , string password); !}2s5b2R.d&~&w`
[DispId(2)] t1^/x:R5L6t,J0x
bool ExecuteSelectCommand(string selCommand);
[DispId(3)]
bool NextRow();
[DispId(4)] OY;P;k~Ma
void ExecuteNonSelectCommand(string insCommand);
[DispId(5)] js:\+UA |
string GetColumnData(int pos); -ys0_L3}`
%Yy?]E5u;m4p_j+t*w
}
// 事件接口Database_COMObjectEvents
[Guid("47C976E0-C208-4740-AC42-41212D3C34F0"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] H.Hg*JS4XV
public interface DBCOM_Events 1n#j!Z.Kc"]:\t
{
} q ~#dtbM
Y|\4_Q
[Guid("9E5E5FB2-219D-4ee7-AB27-E4DBED8E123E"), xhEh(\W8GQ
ClassInterface(ClassInterfaceType.None), c [y)DP@uI1`H
ComSourceInterfaces(typeof(DBCOM_Events))]
public class DBCOM_Class : DBCOM_Interface
{
private SqlConnection myConnection = null ; }4Db6VnMb[J
SqlDataReader myReader = null ; zAm;wuH p O*U
public DBCOM_Class()
{
} _J5Q"i#F/z]R c!?
public void Init(string userid , string password)
{
try
{ \ y^${ O3OM'k` M
string myConnectString = "user id="+userid+";password="+password+ rYK)V1S3@6k.T&l
";Database=NorthWind;Server=SKYWALKER;Connect Timeout=30";
myConnection = new SqlConnection(myConnectString); sJ0{g.D/T
myConnection.Open(); U"H?,V Pc7wQ
MessageBox.Show("CONNECTED"); (QQ[!Ha$B a
}
catch(Exception e)
{ (U1D4?U(S*Cp`9Uh
MessageBox.Show(e.Message);
}
} -gKC|"vF
public bool ExecuteSelectCommand(string selCommand) .Vk(Bx:MD
{ ,FB5r!~5Rad4b iF
if ( myReader != null ) %Y`N `5K4x)@
myReader.Close() ; ;G!B!LRM5?'H
4a@OoV%c
SqlCommand myCommand = new SqlCommand(selCommand);
myCommand.Connection = myConnection;
myCommand.ExecuteNonQuery(); ?R)B RgV7@+F&u
myReader = myCommand.ExecuteReader();
return true ; g ~a-}0d:N
} Vn&FbA)N.X_b+Q^[
1HBx Lg"P
public bool NextRow() gs7]lR9W[bo
{
if ( ! myReader.Read() ) -\"l2at&tQ
{
myReader.Close(); )MS i z'vY
return false ;
} /o5_1?!z3b h5OD#v7}7f/v
return true ; 5Z#`4v\ z6RDA C g
} R[$I!p$g4??