用 .NET 寫 COM 元件的注意事項

分享到噗浪!

之前曾經接了一個案子,需要寫一個元件給 ASP 來呼叫,我最後是採用 .NET 開發出相關功能,然後設定成一個 COM 元件,而當時也有紀錄下整個開發的過程,如下:

1. 開啟 Visual Studio 2005

2. 新增 Class Library 專案

3. 要在專案屬性中的 Build 頁籤勾選 Register for COM interop

4. 註冊 COM 的 Module 名稱為 Class 的 [Namespace].[ClassName]

5. 類別(Class)要引入 System.Runtime.InteropServices 命名空間

using System.Runtime.InteropServices;

6. 在類別定義的地方要加上 [ComVisible(true)] 屬性

以下是一個完整的範例程式:

using System;
using System.Collections.Generic;
using System.Text;

using System.Runtime.InteropServices; 

namespace Miniasp
{
    [ComVisible(true)]
    public class MyFirstCOM
    {
        private string _ErrorMsg; 

        public string ErrorMsg
        {
            get { return _ErrorMsg; }
            set { _ErrorMsg = value; }
        } 

        private int _ErrorNo; 

        public int ErrorNo
        {
            get { return _ErrorNo; }
            set { _ErrorNo = value; }
        } 

        /// <summary>
        /// Applies the domain.
        /// </summary>
        /// <param name="Email">The email.</param>
        /// <param name="DomainName">Name of the domain.</param>
        public void ApplyDomain(string Email, string DomainName)
        {
            throw new System.NotImplementedException();
        } 

        /// <summary>
        /// Removes the domain.
        /// </summary>
        /// <param name="DomainName">Name of the domain.</param>
        public void RemoveDomain(string DomainName)
        {
            throw new System.NotImplementedException();
        }
    }
}

就這麼簡單,接下來就是如何部署的問題了,若要手動部署 .NET 所寫的 COM 元件,可以參考 MSDN 上的這篇文章:部署 Interop 應用程式

以下是我的一些摘要筆記:

1. 手動註冊 COM interop 的指令

gacutil /i MyFirstCOM.dll
Regasm.exe MyFirstCOM.dll /tlb:MyFirstCOM.tlb /register

2. 手動取消註冊 Interop 的指令

Regasm.exe MyFirstCOM.dll /tlb:MyFirstCOM.tlb /unregister

注意:當你註冊 COM 元件成功後,每次在 IIS 執行測試 COM 元件的 ASP 程式後,只要 COM 元件有更新並重新註冊後,都要重新啟動 IIS 或 W3SVC 才會真正生效。你可以執行 iisreset 指令完成 IIS 的重新啟動作業。

iisreset

而若要能自動執行部署工作的話,可以使用 Windows Installer 進行 .NET COM 元件的部署,你可以參考 MSDN 上的這篇文章:Windows Installer 部署疑難排解 學習相關知識。不過因為牽扯到要註冊元件的動作,所以除了將檔案安裝到主機外,我當時還另外寫了兩支 VBScript 程式用來做元件註冊與解除安裝時所需的取消註冊動作。

以下是安裝完成後所需的 VBScript 程式,用以註冊元件:

'PostInstall_RegisterCOM.vbs
'@rem c:
'@rem cd "C:\Program Files\Miniasp\MyFirstCOM" 

Set WshShell = CreateObject("WScript.Shell") 

'這裡的 Property("CustomActionData") 是透過 Windows Installer 傳遞過來的參數
WshShell.CurrentDirectory = Property("CustomActionData") 
'顯示目前的所在目錄(除錯用)
'WScript.Echo WshShell.CurrentDirectory 

WshShell.Run "net stop w3svc",7,True 

WshShell.Run "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Regasm.exe MyFirstCOM.dll /tlb:MyFirstCOM.tlb"            ,7,True
WshShell.Run "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Regasm.exe MyFirstCOM.dll /tlb:MyFirstCOM.tlb /unregister",7,True
WshShell.Run "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Regasm.exe MyFirstCOM.dll /tlb:MyFirstCOM.tlb /register"  ,7,True
WshShell.Run "gacutil /i MyFirstCOM.dll" & """"  ,7,True 

WshShell.Run "net start w3svc",7,True 

Set WshShell = Nothing

以下是解除安裝時所需的 VBScript 程式:

'PostUninstall_UnregisterCOM.vbs
'@rem c:
'@rem cd "C:\Program Files\Miniasp\MyFirstCOM" 

Set WshShell = CreateObject("WScript.Shell") 

WshShell.CurrentDirectory = Property("CustomActionData") 

WshShell.Run "net stop w3svc",7,True 

WshShell.Run "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Regasm.exe MyFirstCOM.dll /tlb:MyFirstCOM.tlb /unregister" ,7,True
WshShell.Run "gacutil /u MyFirstCOM.dll",7,True 

Dim objFSO
Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.DeleteFile "MyFirstCOM.tlb" 

WshShell.Run "net start w3svc",7,True 

Set WshShell = Nothing

最後就是要製作 Windows 安裝程式了:

首先,必須設定 [自訂動作]

  • Commit
    • PostInstall_RegisterCOM.vbs
  • Rollback
    • PostUninstall_UnregisterCOM.vbs
  • Uninstall
    • PostUninstall_UnregisterCOM.vbs

然後要在每一個 [自訂動作] 的屬性視窗編輯 [CustomActionData] 屬性,並輸入:

[TARGETDIR]

這樣就大功告成了!

接下來就是如何在 ASP 程式裡呼叫我們用 .NET 寫的 COM 元件了,底下是一個簡單的範例:

<%
Set Obj = Server.CreateObject("Miniasp.MyFirstCOM")

Obj.ApplyDomain Email, DomainName

If Obj.ErrorNo = 0 Then
    Response.Write("新增成功!")
Else
    Response.Write("新增失敗:" & Obj.ErrorMsg)
End If

Obj.RemoveDomain DomainName
%>

重申一次:只要在 IIS 執行過測試 COM 元件的 ASP 程式,只要 COM 元件有更新並重新註冊後,都要重新啟動 IIS 或 W3SVC 才會真正生效。你可以執行 iisreset 指令完成 IIS 的重新啟動作業。

相關連結

  

此文章由 will 發表於 2008/7/15 上午 09:38:10

永久連結 | 評論 (13) | 此文章的RSSRSS comment feed |

分類: .Net | C# | Visual Studio

標籤: , , ,

評論

七月 18. 2008 16:23

美樂蒂

您好,由於第一次要寫DLL,雖然努力上網找資料,但總覺得基礎不足,網路上的重點文章,常常看了覺得我知道意思,但是寫起來總是缺東漏西的(可能少了那個基本步驟或如何)。

我要用c#寫一隻DLL供ASP使用,請問市面上有什麼書籍可以參考的呢?
或是有什麼資料可以佐以參考的呢?目前不清楚的是如何改成DLL包裝起來 ...

煩請推薦,十分感謝~~

美樂蒂 台灣

七月 18. 2008 18:27

Will 保哥

ASP.NET 2.0 網站個人化與自訂控制項 (Professional ASP.NET 2.0) by 林成毅
tlsj.tenlong.com.tw/.../bookSearchViewAction.do

在以上書籍的 Ch24 商務物件章節有提到。而這本書的「上冊」如下:

ASP.NET 2.0 介面設計與資料存取 (Professional ASP.NET 2.0)
tlsj.tenlong.com.tw/.../bookSearchViewAction.do

這兩本書蠻不錯的,你可以參考看看。

Will 保哥 台灣

八月 6. 2008 10:20

美樂蒂

Will保哥,您好:
謝謝您推薦的書,在閱讀之後,已瞭解該如何處理。本想待該DLL撰寫完成後再跟您致謝。
但是現又遇到一個問題,在書藉中、網路上,初學C#的我實在看不出解決方法,故又來跟您請教,真是不好意思..

因為對C#、.NET 不是很瞭解(之前比較熟悉VB語法,現想改用C來寫看看)我的構想是這樣,如果在執行檔做的出來,那麼移到類別庫中應該只是封裝時不同而已,但事實應該非如此..Orz..所以我先在Windows Form應用程式中將所需程式碼撰寫好、測試成功後。再建一個類別庫,將之前測試好的程式碼移到類別庫的程式碼中,卻在偵錯時被告知「必須是get或set的存取子」–其錯誤的內容為「String limIP = "116.59.161.38";」。有朋友建議用最嚴謹的宣告寫法(註1)後,再使用其變數,但得到相同的錯誤訊息。有參考過微軟本身的範本(msdn.microsoft.com/.../aa287487(VS.71).aspx),但實在看不出問題點。

實在頭痛.若您方便,煩您建議或告知,謝謝!

註1:
        [ComVisible(true)]
        public String Hstart2
        {
            get { return hstart2; }
            set { hstart2 = value; }
        }

美樂蒂 台灣

八月 6. 2008 10:36

will

不好意思,我看不太懂你的問題耶,不知道怎麼給你建議。

will 台灣

八月 6. 2008 11:20

美樂蒂

Will保哥,您好:那我簡化原來程式碼,即使簡化後,偵測還是會出錯,煩請您指導一下,謝謝!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.NetworkInformation;
using System.Management;
using Microsoft.VisualBasic.Devices;

namespace HtmlStart
{
    [ComVisible(true)]
    public class HStart
    {

        [ComVisible(true)]
        public String CreateHtml
        {

            //*** 設定要鎖定的變數 limIP,limMAC
            String limIP = "116.59.161.38";  =>偵測錯誤之處
            String limMAC = "00-53-45-00-00-00";

            int kddd = 1;
        

            //*** Content1Laughingefault_login.asp ***

        }

    }
}

美樂蒂 台灣

八月 6. 2008 12:58

will

這大概是變數或屬性名稱衝突的問題吧,你將整個程式碼看仔細一點,或是重新命名變數一下試試,真正的問題可能跟這一行無關。

will 台灣

八月 6. 2008 13:02

美樂蒂

謝謝建議,我再試試看! ^^

美樂蒂 台灣

八月 8. 2008 13:47

美樂蒂

報告,我找到問題點了!
原來是忘了這一行
using System.Runtime.InteropServices;

感謝Will保哥的協助。 ^^ ~

美樂蒂 台灣

九月 4. 2008 12:05

感溫哦!

感溫哦!剛好用的到,雖然「註冊 COM 的 Module 名稱為 Class 的 [Namespace].[ClassName]」這段看不太懂,

後來自己亂測也讓我弄成功了!

謝謝啦!

感溫哦! 台灣

十一月 11. 2009 13:04

dominic

請問你用的IIS是哪個版本的? 我有一個問題想請教, 就是在vista裡的IIS在執行類似你程式裡呼叫自己寫的dll (Set Obj = Server.CreateObject("Miniasp.MyFirstCOM"))時會有錯誤代碼500的錯誤訊息,因此想請教該怎麼設定II7,謝謝!
我測試過跑一個簡單的response跟request指令時不會有錯誤!!

dominic 台灣

十一月 11. 2009 13:37

Will 保哥

dominic: 我當時用 IIS6,代碼500的錯誤訊息是「伺服器錯誤」,我想可能是因為權限不夠所造成的。

Will 保哥 台灣

十一月 11. 2009 14:02

dominic

感謝您的回應! 我之前在II6裡也是可以跑,但換成vista的作業系統後就變成必須使用IIS7, 同樣的程式碼在IIS7執行上會有500的錯誤訊息,但跑一般簡單的response,request等指令就不會有錯誤!

dominic 台灣

三月 17. 2010 21:08

小胖

保哥您好 :
  我有看到一篇文章
  感覺要寫  .net Com 元件  好像很麻煩
  www.csharphelp.com/.../
  到底 您的寫法  跟  這篇文章的寫法  差在那邊?!

小胖 台灣

新增評論


( 您輸入的Email不會顯示於網站上 )

  Country flag

biuquote
  • 評論
  • 線上預覽
Loading