最近開發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條做好的話,預設設定即可滿足要求)
暫時就這麼多了,還有什麼問題,以後補充