文章編號: 241896 - 上次校閱: 2007年5月18日 - 版次: 5.1

Visual Basic 6.0 ActiveX 元件的執行緒問題

系統提示本文適用於您使用的作業系統之外的作業系統。與您不相關的文章內容已停用。
本文曾發行於 CHT241896

在此頁中

全部展開 | 全部摺疊

徵狀

在多執行緒的環境中使用 Visual Basic 6.0 ActiveX 元件時,您應該會察覺到下列潛在的問題:

ActiveX DLL 位於多執行緒的用戶端中

  • MSVBVM60.DLL 內發生存取違規。
  • 用戶端進入鎖死狀態。
如果 Visual Basic ActiveX DLL 位於多執行緒的環境中,例如 IIS、MTS 或多執行緒的 C 用戶端,以及沒有啟用 [保留於記憶體中] 選項,您可能會看到這兩個徵狀。如果要啟用這個選項,請依照下列步驟進行:
  1. [專案] 功能表,選取 [專案屬性]
  2. [一般] 索引標籤上,確認 [執行緒模型] 是 [Apartment 執行緒],然後選取 [自動執行][保留於記憶體中] 核取方塊*
  3. 儲存專案然後編譯 DLL。
*注意 如果專案含有任何使用者介面元素,例如表單或控制項,[自主式執行] 選項便無法使用。如果沒有選取 [自動執行][保留於記憶體中] 選項就無法使用。

注意 在 Visual Studio 6.0 的 Service Pack 3 之前,如果啟用 [保留於記憶體中],在處理序關閉期間有可能會得到 AV。在最新的 Visual Studio 6.0 Service Pack 中已經修正這個問題:
http://msdn2.microsoft.com/en-us/vstudio/aa718364.aspx' (http://msdn2.microsoft.com/en-us/vstudio/aa718364.aspx)

如果 ActiveX DLL 或 UserControl 專案包含 API 宣告,您可能會在處理序/執行緒關閉期間,或物件建立期間遇到鎖死問題,即使在 ActiveX DLL 專案中選取 [自動執行] 核取方塊,情況也是如此。 如果要解決這個問題,您可以在 Visual Basic 中使用「型別程式庫」,不要使用「宣告」。如需有關如何使用「型別程式庫」的詳細資訊,請按一下下面的文件編號,檢視「Microsoft 知識庫」中的文件:
189133? (http://support.microsoft.com/kb/189133/ ) 如何使用型別程式庫讓 C DLL 更輕鬆存取 VB

由多執行緒的用戶端,或數個單一或多執行緒的用戶端存取的 ActiveX EXE

Runtime error '7':out of memory and sometimes followed by a disk operation error. (執行期間錯誤 '7':記憶體不足以及有時候跟著發生磁碟操作錯誤)
Run-time error '430':Class does not support Automation or does not support expected interface. (執行期間錯誤 '430':類別不支援 Automation 或不支援預期的介面。)
Run-time error '424':Object required. (執行期間錯誤 '424':需要物件)
Run-time error '-2147023170 (800706be)':Automation error.The remote procedure call failed. (執行期間錯誤 '-2147023170 (800706be)':自動化錯誤。遠端程序呼叫失敗。)
Run-time error '-2147287010 (8003001e)':Automation error.This is a "A disk error occurred during a read operation." based on ErrLook. (執行期間錯誤 '-2147287010 (8003001e)':自動化錯誤。依據 ErrLook 這是「讀取作業期間發生的磁碟錯誤」。)
Additional server processes (ThreadTest.EXE) are created even though the Instancing property of Class1 is marked MultiUse. (即使 Class1 的 Instancing 屬性是標記為 MultiUse,還是建立了額外的伺服器處理序 (ThreadTest.EXE))
如果您的 ActiveX 執行檔伺服器具有大於一 (1) 的執行緒集區,且多執行緒的用戶端或多重單一或多執行緒的用戶端,在伺服器內快速建立與破壞物件時,您可能會看見上面所列的錯誤訊息。如果要解決這個問題,您可以在本機伺服器中建立一個空白的類別,並讓用戶端保有對它的參考,如下面<詳細資訊>一節中所示。

狀況說明

這是原本設計的做法,在 Visual Studio 6 Service Pack 5 中,如果專案包含任何 具有 MTSTransactionMode 不是設定為 0 的公用類別,則會自動選取 [自主式執行] 選項和 [保留於記憶體中] 選項。

其他相關資訊

重現問題的步驟

答:建立伺服器

  1. 建立 ActiveX 執行檔專案,並重新命名為 ThreadTest
  2. [專案] 功能表,選取 [專案屬性],在 [一般] 索引標籤上的 [執行緒集區] 選取兩個 (2) 執行緒。
  3. 將下面程式碼新增至預設的類別中 (類別 1):
    Private strClassName As String
    Public Property Let ClassName(ByVal vData As String)
       strClassName = vData
    End Property
    Public Property Get ClassName() As String
       ClassName = strClassName 
    End Property
    					
  4. 儲存並編譯專案 (ThreadTest.EXE)。

B:建立用戶端並測試

  1. 建立「標準執行檔」專案,並重新命名為 Client
  2. 在預設表單上 (表單 1) 新增一個命令按鈕和文字方塊。
  3. 將下列程式碼新增至表單 1:
    Private Sub Command1_Click()
       Dim i As Long, j As Long
       Dim o As Object
       j = Val(Text1.Text)
       For i = 1 To j
          DoEvents
          Set o = CreateObject("ThreadTest.Class1")
          o.ClassName = i
          Me.Caption = o.ClassName
          Set o = Nothing
       Next
    End Sub
    Private Sub Form_Load()
       Text1.Text = 1000
       Command1.Caption = "Start"
    End Sub
    					
  4. 編譯此專案 (Client.EXE)。
  5. 啟動三個或更多的 Client.EXE 執行個體,然後按下每個表單上的 [開始] 按鈕。請注意,您會看見上述的一個或多個錯誤訊息。

C:實作解決方案

  1. 開啟 ThreadTest 專案。
  2. 新增另一個沒有程式碼的類別模組 (類別 2)。
  3. 儲存並重新編譯此專案 (ThreadTest.EXE)。
  4. 開啟 Client 專案。
  5. 使用下面程式碼來取代表單 1 中的程式碼:
    Private p As Object
    Private Sub Command1_Click()
       Dim i As Long, j As Long
       Dim o As Object
       j = Val(Text1.Text)
       For i = 1 To j
          DoEvents
          Set o = CreateObject("ThreadTest.Class1")
          o.ClassName = i
          Me.Caption = o.ClassName
          Set o = Nothing
       Next
    End Sub
    Private Sub Form_Load()
       Text1.Text = 1000
       Command1.Caption = "Start"   
       Set p = CreateObject("ThreadTest.Class2")
    End Sub
    Private Sub Form_Unload(Cancel As Integer)
       Set p = Nothing
    End Sub
    					
  6. 儲存並重新編譯此專案 (Client.EXE)。
  7. 執行三個或更多的 Client.EXE 執行個體,然後按下每個表單上的 [開始] 按鈕。請注意,您應該不會看見任何錯誤訊息。
如果多個用戶端經由 DCOM 存取 ActiveX 執行檔,其中包含大於一的執行緒集區,則<詳細資訊>一節的 C 部分所述的解決方案無法使用。因此,Visual Basic 6.0 ActiveX 執行緒伺服器並不適合具有多個快速建立與破壞物件的用戶端的 DCOM 伺服器。如果您的伺服器應用程式需要處理這種情況,我們強烈建議在 MTS 中使用 ActiveX DLL 來替代。設計 ActiveX DLL 進駐 MTS 中時,請確認已經選取了 [自動化執行][保留於記憶體中] 核取方塊。如果要找出這些核取方塊的所在位置,請從 [專案] 功能表,選取 [專案屬性],然後選取 [一般] 索引標籤。

如果您想要在 MTS 或 COM+ 下使用 ActiveX 元件,請不要使用 [GlobalMultiUse Instancing] 類別屬性。GlobalMultiUse 物件的介面是在個別執行緒的表格中快取,並且在執行緒終止時才能釋放出來。因此,如果傳來某個具有不同內容的呼叫 (雖然是在同一個執行緒上),此呼叫會因 RPC_E_WRONG_THREAD 而失敗。如果要在 MTS 與 COM+ 中使用元件,您應該要以物件沒有狀態的方式設計類別。

這篇文章中的資訊適用於:
  • Microsoft Visual Studio 6.0 Service Pack 3
  • Microsoft Visual Studio 6.0 Enterprise Edition
  • Microsoft Visual Basic 6.0 Professional Edition
  • Microsoft Visual Basic 6.0 Enterprise Edition
關鍵字:?
kbprb kbthread kbtophit KB241896
Microsoft及(或)其供應商不就任何在本伺服器上發表的文字資料及其相關圖表資訊的恰當性作任何承諾。所有文字資料及其相關圖表均以「現狀」供應,不負任何擔保責任。Microsoft及(或)其供應商謹此聲明,不負任何對與此資訊有關之擔保責任,包括關於適售性、適用於某一特定用途、權利或不侵權的明示或默示擔保責任。Microsoft及(或)其供應商無論如何不對因或與使用本伺服器上資訊或與資訊的實行有關而引起的契約、過失或其他侵權行為之訴訟中的特別的、間接的、衍生性的損害或任何因使用而喪失所導致的之損害、資料或利潤負任何責任。