﻿# 用 .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 應用程式](http://msdn2.microsoft.com/zh-tw/library/tc0204w0\(VS.80\).aspx)。

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

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 部署疑難排解](http://msdn2.microsoft.com/zh-tw/library/kz0ke5xt\(vs.80\).aspx) 學習相關知識。不過因為牽扯到要註冊元件的動作，所以除了將檔案安裝到主機外，我當時還另外寫了兩支 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 的重新啟動作業。

**相關連結**

-   [How to deploy an assembly to the target computer global assembly cache](https://learn.microsoft.com/en-us/dotnet/framework/app-domains/install-assembly-into-gac)
-   [組件登錄工具 (Regasm.exe)](http://msdn2.microsoft.com/zh-tw/library/tzat5yw6\(VS.80\).aspx)
-   [Java. Javascript, WSH and PB How-to](http://www.rgagnon.com/) - 這裡有些 [WSH 的 Tips](https://web.archive.org/web/20080225021431/http://64.18.163.122:80/rgagnon/topics/wsh-vbs.html)
