天天看點

ACTIVEX控件無法顯示的問題

最近開發ACTIVEX 用于上傳檔案

但是遇到一個最嚴重的問題,在客戶機上無法顯示

經過大量的資料查閱,終于發現了問題根源!

首先,ACTIVEX要在使用者機上正确的安裝和注冊肯定是需要一個數字簽名的,當然,如果手動安裝和注冊,可以忽略這個,不過要用于INTERNET上使用,最好還是使用數字簽名,否則很不友善。

其次,在IE6或更高版本上使用,ACTIVEX控件還需要申明安全接口(IobjectSafety接口) ,這個就是遇到的問題根源。

起初在做好控件後,使用證書進行了簽名,但是仍然在使用者機器上無法顯示,很是奇怪,到處查找資料,控件注冊、安裝、簽名,各個方面都正确操作了,還是不行,最後在一騙關于安全接口申明的文章上找到了答案!

文章内容如下:

如何在VB中實作ActiveX控件的IobjectSafety接口

--------------------------------------------------------------------------------

總述

本文叙述了如何在VB中實作控件的IobjectSafety接口,以标志該控件是腳本安全和初始化安全的。VB控件預設的處理方式是在系統資料庫中注冊元件類來辨別其安全性,但實作IobjectSafety接口是更好的方法。本言語包括了實作過程中所需的所有代碼。

請注意,控件隻有确确實實是安全的,才能被辨別為“安全的”。本文并未論及如何確定控件的安全性,這個問題請參閱Internet Client Software Development Kit (SDK)中的相關文檔 "Safe Initialization and Scripting for ActiveX Controls",它在Component Development 欄目中。

相關資訊:

<此處略去了一段也許無關緊要的警告>

現在開始循序漸進地舉例說明怎樣建立一個簡單的VB控件,以及怎樣将它辨別為腳本安全和初始化安全。

首先建立一個檔案夾來存放在本例中所産生的檔案。

從VB CD-ROM取得OLE 自動化類庫的制作工具。将VB安裝CD光牒中/Common/Tools/VB/Unsupprt/Typlib/目錄下所有内容一并拷貝到前面建立的項目檔案夾中。

把下列内容拷貝到“記事本”中,然後儲存到上述檔案夾,檔案名為Objsafe.odl:

      [

          uuid(C67830E0-D11D-11cf-BD80-00AA00575603),

          helpstring("VB IObjectSafety Interface"),

          version(1.0)

      ]

      library IObjectSafetyTLB

      {

          importlib("stdole2.tlb");

          [

              uuid(CB5BDC81-93C1-11cf-8F20-00805F2CD064),

              helpstring("IObjectSafety Interface"),

              odl

          ]

          interface IObjectSafety:IUnknown {

              [helpstring("GetInterfaceSafetyOptions")]

              HRESULT GetInterfaceSafetyOptions(

                        [in]  long  riid,

                        [in]  long *pdwSupportedOptions,

                        [in]  long *pdwEnabledOptions);

              [helpstring("SetInterfaceSafetyOptions")]

              HRESULT SetInterfaceSafetyOptions(

                        [in]  long  riid,

                        [in]  long  dwOptionsSetMask,

                        [in]  long  dwEnabledOptions);

           }

       }

在指令行提示符下切換到項目檔案夾,輸入下列指令建立一個.tlb 檔案:

MKTYPLIB objsafe.odl /tlb objsafe.tlb

在VB中建立一個ActiveX Control 項目。修改屬性,把項目命名為IobjSafety,控件命名為DemoCtl。在控件上放置一個按鈕,命名為cmdTest,在它的Click事件中加入一句代碼 MsgBox "Test" 。

打開菜單“工程->引用”,點“浏覽”,找到剛剛建立的Objsafe.tlb,把它加入到引用中。

增加一個新module名為basSafeCtl,并在其中加入下列代碼:

      Option Explicit

      Public Const IID_IDispatch = "{00020400-0000-0000-C000-000000000046}"

      Public Const IID_IPersistStorage = _

        "{0000010A-0000-0000-C000-000000000046}"

      Public Const IID_IPersistStream = _

        "{00000109-0000-0000-C000-000000000046}"

      Public Const IID_IPersistPropertyBag = _

        "{37D84F60-42CB-11CE-8135-00AA004BB851}"

      Public Const INTERFACESAFE_FOR_UNTRUSTED_CALLER = &H1

      Public Const INTERFACESAFE_FOR_UNTRUSTED_DATA = &H2

      Public Const E_NOINTERFACE = &H80004002

      Public Const E_FAIL = &H80004005

      Public Const MAX_GUIDLEN = 40

      Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _

         (pDest As Any, pSource As Any, ByVal ByteLen As Long)

      Public Declare Function StringFromGUID2 Lib "ole32.dll" (rguid As _

         Any, ByVal lpstrClsId As Long, ByVal cbMax As Integer) As Long

      Public Type udtGUID

          Data1 As Long

          Data2 As Integer

          Data3 As Integer

          Data4(7) As Byte

      End Type

      Public m_fSafeForScripting As Boolean

      Public m_fSafeForInitializing As Boolean

      Sub Main()

          m_fSafeForScripting = True

          m_fSafeForInitializing = True

      End Sub

在工程屬性中把啟動對象改成Sub Main確定上述代碼會被執行。m_fSafeForScripting 和m_fSafeForInitializing兩件變量的值分别指定了腳本安全和初始化安全取值。

打開控件代碼視窗,在聲明部分加入如下代碼(如果有Option Explicit語句,當然要保證代碼放在其後):

Implements IObjectSafety

把下面兩個過程代碼拷貝到控件代碼中:

      Private Sub IObjectSafety_GetInterfaceSafetyOptions(ByVal riid As _

      Long, pdwSupportedOptions As Long, pdwEnabledOptions As Long)

          Dim Rc      As Long

          Dim rClsId  As udtGUID

          Dim IID     As String

          Dim bIID()  As Byte

          pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER Or _

                                INTERFACESAFE_FOR_UNTRUSTED_DATA

          If (riid <> 0) Then

              CopyMemory rClsId, ByVal riid, Len(rClsId)

              bIID = String$(MAX_GUIDLEN, 0)

              Rc = StringFromGUID2(rClsId, VarPtr(bIID(0)), MAX_GUIDLEN)

              Rc = InStr(1, bIID, vbNullChar) - 1

              IID = Left$(UCase(bIID), Rc)

              Select Case IID

                  Case IID_IDispatch

                      pdwEnabledOptions = IIf(m_fSafeForScripting, _

                    INTERFACESAFE_FOR_UNTRUSTED_CALLER, 0)

                      Exit Sub

                  Case IID_IPersistStorage, IID_IPersistStream, _

                     IID_IPersistPropertyBag

                      pdwEnabledOptions = IIf(m_fSafeForInitializing, _

                    INTERFACESAFE_FOR_UNTRUSTED_DATA, 0)

                      Exit Sub

                  Case Else

                      Err.Raise E_NOINTERFACE

                      Exit Sub

              End Select

          End If

      End Sub

      Private Sub IObjectSafety_SetInterfaceSafetyOptions(ByVal riid As _

      Long, ByVal dwOptionsSetMask As Long, ByVal dwEnabledOptions As Long)

          Dim Rc          As Long

          Dim rClsId      As udtGUID

          Dim IID         As String

          Dim bIID()      As Byte

          If (riid <> 0) Then

              CopyMemory rClsId, ByVal riid, Len(rClsId)

              bIID = String$(MAX_GUIDLEN, 0)

              Rc = StringFromGUID2(rClsId, VarPtr(bIID(0)), MAX_GUIDLEN)

              Rc = InStr(1, bIID, vbNullChar) - 1

              IID = Left$(UCase(bIID), Rc)

              Select Case IID

                  Case IID_IDispatch

                      If ((dwEnabledOptions And dwOptionsSetMask) <> _

                   INTERFACESAFE_FOR_UNTRUSTED_CALLER) Then

                          Err.Raise E_FAIL

                          Exit Sub

                      Else

                          If Not m_fSafeForScripting Then

                              Err.Raise E_FAIL

                          End If

                          Exit Sub

                      End If

                  Case IID_IPersistStorage, IID_IPersistStream, _

                IID_IPersistPropertyBag

                      If ((dwEnabledOptions And dwOptionsSetMask) <> _

                    INTERFACESAFE_FOR_UNTRUSTED_DATA) Then

                          Err.Raise E_FAIL

                          Exit Sub

                      Else

                          If Not m_fSafeForInitializing Then

                              Err.Raise E_FAIL

                          End If

                          Exit Sub

                      End If

                  Case Else

                      Err.Raise E_NOINTERFACE

                      Exit Sub

              End Select

          End If

      End Sub

儲存後,把工程編譯成OCX檔案。現在控件已經實作了IObjectSafety 接口。在.htm中加入這件控件試一試吧。

經過以上資料的指導,終于在使用者機器上顯示了控件。

總結:

要使使用者機器正常使用ACTIVEX控件,必須滿足以下條件

1、程式代碼必須正确(這雖然是廢話,但是有時候很多大問題總是出現在很白癡的地方)

2、使用者機器必須正确安裝和注冊控件(最常見的方法當然就是通過自動下載下傳安裝,這個需要數字簽名,當然手動也可以)

3、控件必須申明安全接口(新手常長忽略掉這個重要部分)

4、IE浏覽器設定(前3條做好的話,預設設定即可滿足要求)

暫時就這麼多了,還有什麼問題,以後補充