现在的位置: 首页 > 综合 > 正文

用C#寫COM組件

2013年11月21日 ⁄ 综合 ⁄ 共 6613字 ⁄ 字号 评论关闭

步驟一:
建立“windows控制項程式庫”工程,如圖: jiangligongcheng.bmp
步驟二:
在我們這個例子中用不到帶界面的com控件所以我們將界面的size屬性設置為 0, 0
我們要用C#寫COM組件必須要實現  public interface IObjectSafety接口因為這是。IObjectSafety接口,把ActiveX控件标记为安全的ActiveX控件。每個接口需要一個GUID特性。要生成變個唯一的Guid,需要運行guidgen.exe工具軟體,要選擇第四項“Registry Format” 如圖:guidgen.bmp
我們還有定義一個接口如下
[Guid("1B1DFAE7-FC2E-4f05-BC5A-5267408EF2A9")]
 public interface IOLpt1
 {
  [DispId(1)] bool WriteCommand(string com,string flag);
  [DispId(2)] void WhenLoad();
 }
功能是提供一個其他語言利用我們所寫的方法的接口。如果不用接口的話其他語言將無法使用我們在程序裡面定義的方法(我在其他的地方也看到過不用接口的例子,不知道為什麼,在我的電腦上如果不用接口編譯隻後將看不到我定義的方法)。這個接口定義了兩個方法分別是 bool WriteCommand(string com,string flag); 和 void WhenLoad();
第一個方法是將命令寫入到並口,第二個方法是當控件啟動的時候讀取Access的命令的內碼並存如到數組中。這裡我們隻介紹如何寫COM組件,其他的將不涉及。
定義類 UserControl1 繼承 System.Windows.Forms.UserControl 實現接口IOLpt1於IObjectSafety

 [Guid("AC8C1E64-B501-4f8b-A026-B4F1D8EF7DF2")]
 [ ClassInterfaceAttribute(ClassInterfaceType.AutoDual) ]
 public class UserControl1 : System.Windows.Forms.UserControl,IOLpt1,IObjectSafety
步驟三
我們還要給我們的控件一個強名。強名需要用sn.exe來得到 命令格式
sn -k myKey.snk 將得到的強名文件myKey.snk復制到你的工程的目錄下,並在我們的工程文件 AssemblyInfo.cs裡面的[assembly: AssemblyKeyFile("")]項中加入你的強名的絕對路徑F:/webpriteCon/PrintExe/mykey.snk
例如:[assembly: AssemblyKeyFile("F://webpriteCon//PrintExe//mykey.snk")]
步驟四
如圖:shuxing
將建置項裡面的「注冊COM組件Interop」項設置為true然後編譯隻後就可以注冊到其他的機器讓別的語言進行引用了。
下面是詳細代碼。
我將陸續寫出如何將COM組件發布成ActiveX控件。

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Data.OleDb;

namespace PrintExe
{
 /*必須要實現IObjectSafety接口,
  * 把ActiveX控件標記為安全的ActiveX控件。
  * IObjectSafety 的實現方式如下
  */
 [Guid("10615515-3979-4f87-A0C9-F786F050AE8B"),InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
 public interface IObjectSafety
 {
  // methods
  [DispId(1)] void GetInterfacceSafyOptions(
   System.Int32 riid,
   out System.Int32 pdwSupportedOptions,
   out System.Int32 pdwEnabledOptions);
  [DispId(2)] void SetInterfaceSafetyOptions(
   System.Int32 riid,
   System.Int32 dwOptionsSetMask,
   System.Int32 dwEnabledOptions);
 }

 [Guid("1B1DFAE7-FC2E-4f05-BC5A-5267408EF2A9")]
 public interface IOLpt1
 {

  [DispId(1)] bool WriteCommand(string com,string flag);
  [DispId(2)] void WhenLoad();
 }

 [Guid("AC8C1E64-B501-4f8b-A026-B4F1D8EF7DF2")]
 [ ClassInterfaceAttribute(ClassInterfaceType.AutoDual) ]
 public class UserControl1 : System.Windows.Forms.UserControl,IOLpt1,IObjectSafety
 {
  string sqlStr;
  static string connStr = @"Jet OLEDB:Global Partial Bulk Ops=2;Jet OLEDB:Registry Path=;Jet OLEDB:Database Locking Mode=1;Data Source='C://printTypeDB.mdb';Mode=Share Deny None;Jet OLEDB:Engine Type=5;Provider='Microsoft.Jet.OLEDB.4.0';Jet OLEDB:System database=;Jet OLEDB:SFP=False;persist security info=False;Extended Properties=;Jet OLEDB:Compact Without Replica Repair=False;Jet OLEDB:Encrypt Database=False;Jet OLEDB:Create System Database=False;Jet OLEDB:Don't Copy Locale on Compact=False;User ID=Admin;Jet OLEDB:Global Bulk Transactions=1";

  OleDbConnection myConn = new OleDbConnection(connStr);
  OleDbCommand myComm;
  OleDbDataReader myDr;
  public string comlist="";
  string[,] myArray;

  private System.ComponentModel.Container components = null;

  public UserControl1()
  {
   InitializeComponent();
  }
  protected override void Dispose( bool disposing )
  {
   if( disposing )
   {
    if( components != null )
     components.Dispose();
   }
   base.Dispose( disposing );
  }

  #region 元件設計工具產生的程式碼
  /// <summary>
  /// 此為設計工具支援所必須的方法 - 請勿使用程式碼編輯器修改
  /// 這個方法的內容。
  /// </summary>
  private void InitializeComponent()
  {
   //
   // UserControl1
   //
   this.Name = "UserControl1";
   this.Size = new System.Drawing.Size(0, 0);

  }
  #endregion
#region IOLpt1 成員

  public bool WriteCommand(string com,string flag)
  {
   //MessageBox.Show("WriteCommand方法已經運行","Error");
   //com為指令碼 str為要列印字符串
   ExeFunction ef = new ExeFunction();
   string[] str = com.Split(new Char[]{'~'});
   //開始將textBox中的外碼取出找到數組中對應的指令碼組成完整的指令
   string Instruction = "";
   string outI = str[0].Trim();
   if(outI!="SET")
   {
    for(int i = 0;i<myArray.Length/5;i++)
    {
     if(myArray[i,0].Trim() == outI)
     {
      char temp1 = Convert.ToChar(Convert.ToInt32(myArray[i,1].Trim()));
      char temp2='1';

      Instruction = temp1.ToString();

      if(myArray[i,2].Trim() != "")
      {
       temp2 = Convert.ToChar(Convert.ToInt32(myArray[i,2].Trim()));
       Instruction += temp1.ToString();
      }

      if(myArray[i,3].Trim() != "")
       Instruction += myArray[i,3].Trim();
    
      Instruction += str[1] + Convert.ToChar(Convert.ToInt32(myArray[i,4].Trim()));
      comlist += Instruction + "~";
      if(flag == "0") //則將指令預存起來
       return true;     
      //MessageBox.Show("方法已經運行完畢","Error");
     }
    }
    if(comlist!="")
    {
     string[] str1 = comlist.Split(new Char[]{'~'});
     comlist="";
     for(int j=0;j<str1.Length-1;j++)
     {
      byte[] buffer = System.Text.Encoding.Default.GetBytes(str1[j]);
      ef.StartP(buffer);
     }
    }
   }else if(outI == "SET") //如果為SET則為設置本機收銀機
   {
    sqlStr = "update printTypeSet set Flag = false";
    myComm = new OleDbCommand(sqlStr,myConn);
    myConn.Open();
    myDr = myComm.ExecuteReader();
    myDr.Close();
    sqlStr = "update printTypeSet set Flag = true where PrintType='" + str[1].Trim() + "'";
    myComm = new OleDbCommand(sqlStr,myConn);
    int i = myComm.ExecuteNonQuery();
    myDr.Close();
    myConn.Close();
    if(i>0)
     MessageBox.Show("設定成功!","OK");
    else
     MessageBox.Show("沒有合適的型號!","OK");
   }
   return true;
  }

  public void WhenLoad()
  {
   //MessageBox.Show("WhenLoad方法已經運行","Error");
   int i = 0;
   //先取得資料的行數
   //將資料取出放入到數組裡面
   try
   {
    sqlStr = "SELECT count(*) FROM printTypeSet WHERE Flag = true";
    myComm = new OleDbCommand(sqlStr,myConn);
    myConn.Open();
    myDr = myComm.ExecuteReader();
    if(myDr.HasRows)
    {
     while(myDr.Read())
     {
      i = (int)myDr[0];
     }
    }
    myDr.Close();
    myArray = new string[i,5];
    sqlStr = "SELECT Instruction,FirstI,SecondI,Parameter,EndI FROM printTypeSet WHERE Flag = true";
    myComm = new OleDbCommand(sqlStr,myConn);
    myDr = myComm.ExecuteReader();
    i = 0;
    if(myDr.HasRows)
    {
     while(myDr.Read())
     {
      myArray[i,0] = myDr[0].ToString();
      myArray[i,1] = myDr[1].ToString();
      myArray[i,2] = myDr[2].ToString();
      myArray[i,3] = myDr[3].ToString();
      myArray[i,4] = myDr[4].ToString();
      i++;
     }
    }
    myDr.Close();
   }
   catch(Exception ex)
   {
    MessageBox.Show("WhenLoad方法運行錯誤" + ex.ToString(),"Error");
   }
   finally
   {
    myConn.Close();
    //MessageBox.Show("方法已經運行完畢","Error");
   }
  }

  #endregion

  #region IObjectSafety 成員

  public void GetInterfacceSafyOptions(Int32 riid, out Int32 pdwSupportedOptions, out Int32 pdwEnabledOptions)
  {
   // TODO:  加入 UserControl1.GetInterfacceSafyOptions 實作
   pdwSupportedOptions = new Int32 ();
   pdwEnabledOptions = new Int32 ();
  }

  public void SetInterfaceSafetyOptions(Int32 riid, Int32 dwOptionsSetMask, Int32 dwEnabledOptions)
  {
   // TODO:  加入 UserControl1.SetInterfaceSafetyOptions 實作
  }

  #endregion
 }
}

简单的做法就是:

按照上面说的建个DLL工程,写个接口和具体实现类,给他们一个GUID,并签名DLL
就如--从COM组件调用.NET组件编程实战 上所说的.然后1.生成类型库;2.注册类型库;3.安装到GAC;就如--如何创建COM组件能够调用的.NET装配件上所说的.

抱歉!评论已关闭.