新手问一下,C#能写COM组件吗,我看了一下没找到。用VC++写COM太麻烦,而且他自动生成的代码有的还有错误,很不好用。

解决方案 »

  1.   

    可以,以下是转贴:用C#寫COM組件步驟一:
    建立“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
      

  2.   

    #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
     }
    }
      

  3.   

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

  4.   

    http://www.csdn.net/develop/Read_Article.asp?id=23438