小小抱怨下:也許是MFC如今用的人少的緣故。在國內和國外都基本上找不到什麼全的資料。特別是ocx打包成Cab時的安裝文件inf的編寫方面,國內基本上是copy,抄的還只知其一;不知其二。查找個資源真心的累啊。如今將編寫步驟和遇到的問題以及問題的解決辦法記錄下來。有的資源是參考了別人的博文,有引用的地方將附上鍊接,再次感謝這些博主,若有侵權,請聯繫本人,當即刪除。html
1、MFC Activex 項目的構建java
此處使用的是:vs2015,操做按照圖片順序,沒有特別注意的地方不作文字註釋了。(不詳細的地方能夠參考:http://www.javashuo.com/article/p-xxyqecuz-nd.html)c++
第一:新建項目web
activexdemo項目建立完成的目錄結構瀏覽器
第2、先介紹四個文件安全
activexdemo.cpp、activexdemoCtrl.cpp、activexdemoPropPage.cpp、activexdemo.idlapp
(1) activexdemo.cpp文件中定義了DllRegisterServer和DllUnregisterServer,能夠發現ActiveX的註冊和反組冊都與該類有關less
(2)activexdemoCtrl.cpp文件jsp
能夠發現該頭文件中聲明瞭消息映射(讓ActiveX控件程序能夠接受系統發送的事件通知,如窗體建立和關閉事件),調度映射(讓外部調用程序(包含ActiveX的容器)能夠方便地訪 問ActiveX控件的屬性和方法),事件映射(讓ActiveX控件能夠向外部調用程序(包含ActiveX的容器)發送事件通知)。也就是說對ActiveX控件的窗口操做都將在這個類中完成,包括 ActiveX控件的建立,重繪,以及在此類中建立可視MFC窗體。函數
(3)activexdemoPropPage.cpp:顯示ActiveX控件的屬性頁的
(4)activexdemo.idl:對外接口定義文件
第3、定義調度映射和事件映射方法,提供給外部調用者使用
(1)經過類視圖進行定義:
在_Dactivexdemo上鼠標右鍵:
以添加對外接口方法BSTR initDvr(BSTR info, BSTR appKey, BSTR accessToken, LONG rowNum, FLOAT height);方法爲例。BSTR爲MFC中的數據類型。不懂的能夠去百度瞭解。
點擊下一步
填寫完信息後點擊完成,外部就能夠調用方法initDvr,同時ActiveX控件項目代碼的內部將會在三個文件中新增代碼:
第4、Release生成ocx文件。並註冊。
項目上右鍵->屬性->常規->項目默認值->MFC的使用,設置爲"在靜態庫中使用MFC",必須。若是不設置,在其餘非開發環境電腦中會出現找不到DLL的錯誤。
在本地磁盤找到生成的activexdemo.ocx,此處路徑爲:E:\c++\activexdemo\Release。找到本身的項目地址中的Release文件夾。
註冊activexdemo.ocx手動註冊:
以管理員權限運行cmd(不會的百度)。
進入activexdemo.ocx的路徑,使用regsvr32 xxx.ocx 對Activex進行註冊。成功會彈出提示框。補充:regsvr32 xxx.ocx -u 對Activex控件進行反註冊。
第5、Activex控件測試
(1)第一種方法:使用ActiveX Control Test Container。ActiveX Control Test Container工具下載。
將下載的控件解壓後複製到安裝的visual studio的安裝根目錄。
添加ActiveX Control Test Container到vs中。
添加完成再次點擊工具菜單,點擊開始測試:
給initDvr方法添加個MessageBox彈出信息:
找到activexdemoCtrl.cpp中的initDvr方法添加:
項目右鍵,點擊從新生成,從新生成ocx文件。而後使用regsvr32 activedemo.ocx -u反註冊下,再使用regsvr32 activedemo.ocx再次註冊下。
此處可能會出現此種錯誤,可按照紅色字體提示解決:
而後再次點擊active container control,進行initDvr方法接口的測試。測試結果以下:
(2)html測試:使用<object></object>標籤。在測試以前須要對activexdemo.ocx進行打包。此處打包成cab包。cab包須要下載cabarc.exe工具以及編寫inf安裝文件。cabarc.exe工具下載。
2.1 cabarc.exe下載以後建議將文件夾配置到系統環境(不懂的本身去百度,此處再也不討論)中。方便在其餘文件夾中使用cabarc.exe命令。
2.2 對inf安裝文件的編寫。此爲最重要。先以該項目爲實例,以後會講到子目錄打包cab。
使用windwos自帶的記事本創建一個inf文件。
打開activexdemo.inf文件進行編寫:(inf的各節的詳細解釋請參考博文:http://www.javashuo.com/article/p-bbmxgfag-hh.html)。
在桌面新建一個文件夾,命名爲activedemo(名稱本身定義)。將Release文件夾下的activexdemo.ocx,上面編寫好的activexdemo.inf文件拷貝到新建的activedemo文件夾中。
打開一個新的cmd,進入到activedemo文件夾。進行cab打包。打包命令:cabarc -r -p N xxx.cab *。此命令爲打包activedemo下的全部文件,包括子文件夾。
新建一個web項目。此處使用java web工程:
在webcontent(web)下新建一個files目錄,並將打包好的cab文件複製到下面。並在index.jsp中添加<object></object>代碼。注意version=1,0,0,0。1,0,0,0之間是,而不是.
詳細以下:
發佈web項目後測試。此處要設置IE瀏覽器容許未簽名的activex控件進行安裝和運行。不懂的百度。
測試結果以下:
此處講下多個目錄打包成cab的inf文件編寫。假設activexdemo.ocx控件須要依賴test.dll和depends文件夾下的test1.dll兩個動態依賴DLL。文件夾結構以下
inf的編寫:
因爲此處的DLL依賴爲示例,不真實存在,故沒法測試,只是以此來說解多層目錄資源打包成cab包。
第6、添加MFC窗體。就是一個帶界面的ActiveX控件
去掉上邊的「肯定」和「取消」按鈕,而後修改對話框屬性:Border改成None,Control改成Ture,ID改成IDD_DIALOG1,Style改成Child,System改成False,Visible改成True,而後在對話框中雙擊,爲對話框添加一個類,以下圖:
點擊完成,會自動新增了一個類:
在對話框上新增一個按鈕,用於測試:
雙擊該按鈕,添加一個點擊事件。在CMyDlg.h和CMyDlg.cpp文件中會響應的增長該事件的代碼:
將剛建立好的MFC對話框添加到Active中。在activexdemoCtrl.h中引入MyDlg.h並添加一個屬性:
而後在activexdemoCtrl類中定義兩個消息映射:窗體建立完成消息映射(WM_CREATE)和窗體改變大小消息映射(WM_SIZE)
在VS2015的菜單項「項目」--》「類嚮導」中,選擇要添加到的項目和類中,選擇「消息」選項卡,選擇WM_CREATE後點擊」添加處理程序「按鈕和選擇WM_SIZE
後點擊」添加處理程序「,這樣在「現有的處理程序」中就有OnCreate和OnSize這兩個函數,點擊肯定,完成消息映射函數的添加,如圖:
點擊應用和完成後,在activexdemoCtrl.h和activexdemoCtrl.cpp文件中會自動添加OnCreate()和OnSize()方法。並在activexdemoCtrl.cpp中添加MFC建立的對話框。
從新生成ocx,而後再次反註冊和註冊,進行測試。結果以下:
第7、ocx更新:
上面註冊的ocx在註冊表中沒有InstalledVersion這個項,須要在inf文件中添加。
inf編輯添加InstalledVersion。若是不添加,可能會出現IE瀏覽器刷新後一直提示須要重複安裝Activex控件。
inf添加了AddReg後的註冊表項:
第8、關於ocx控件已經安裝成功,但出現「SCRIPT438:對象不支持"xxx"屬性或者方法」。以這篇的例子來講,IE瀏覽器中的Console中會出現錯誤:「SCRIPT438:對象不支持"initDvr"屬性或者方法「的解決辦法。
(1)找到IE瀏覽器上的設置->Internet選項->安全->找到Internet、本地Internet、受信任的站點三個項目下的->自定義級別->找到"對未標記爲可安全執行腳本的Activex控件初始化並執行腳本"設置爲"啓用"。
(2)1的方法太過麻煩,不可讓每臺電腦都設置。故經過添加IObjectSafety接口。
在activexdemoCtrl.h中添加:
代碼可複製:
//ISafeObject Begin DECLARE_INTERFACE_MAP() BEGIN_INTERFACE_PART(ObjSafe, IObjectSafety) STDMETHOD_(HRESULT, GetInterfaceSafetyOptions)( /*[in]*/ REFIID riid, /*[out]*/ DWORD __RPC_FAR *pdwSupportedOptions, /*[out]*/ DWORD __RPC_FAR *pdwEnabledOptions ); STDMETHOD_(HRESULT, SetInterfaceSafetyOptions)( /*[in]*/ REFIID riid, /*[in]*/ DWORD dwOptionSetMask, /*[in]*/ DWORD dwEnabledOptions ); END_INTERFACE_PART(ObjSafe); //ISafeObject END
在activexdemoCtrl.cpp中添加:
代碼可複製:
/* * IObjectSafety BEGIN */ //Interface map for IObjectSafety BEGIN_INTERFACE_MAP(CactivexdemoCtrl, COleControl) INTERFACE_PART(CactivexdemoCtrl, IID_IObjectSafety, ObjSafe) END_INTERFACE_MAP() //IObjectSafety member functions //Delegate AddRef,Release,QueryInterface ULONG FAR EXPORT CactivexdemoCtrl::XObjSafe::AddRef() { METHOD_PROLOGUE(CactivexdemoCtrl, ObjSafe) return pThis->ExternalAddRef(); } ULONG FAR EXPORT CactivexdemoCtrl::XObjSafe::Release() { METHOD_PROLOGUE(CactivexdemoCtrl, ObjSafe) return pThis->ExternalRelease(); } HRESULT FAR EXPORT CactivexdemoCtrl::XObjSafe::QueryInterface( REFIID iid, void FAR* FAR* ppvObj) { METHOD_PROLOGUE(CactivexdemoCtrl, ObjSafe) return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj); } const DWORD dwSupportedBits = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA; const DWORD dwNotSupportedBits = ~dwSupportedBits; // CStopLiteCtrl::XObjSafe::GetInterfaceSafetyOptions // Allows container to query what interfaces are safe for what. We're // optimizing significantly by ignoring which interface the caller is // asking for. HRESULT STDMETHODCALLTYPE CactivexdemoCtrl::XObjSafe::GetInterfaceSafetyOptions( REFIID riid, DWORD __RPC_FAR *pdwSupportedOptions, DWORD __RPC_FAR *pdwEnabledOptions) { METHOD_PROLOGUE(CactivexdemoCtrl, ObjSafe) HRESULT retval = ResultFromScode(S_OK); // does interface exist? IUnknown FAR* punkInterface; retval = pThis->ExternalQueryInterface(&riid, (void * *)&punkInterface); if (retval != E_NOINTERFACE) { // interface exists punkInterface->Release(); // release it--just checking! } // we support both kinds of safety and have always both set, // regardless of interface *pdwSupportedOptions = *pdwEnabledOptions = dwSupportedBits; return retval; // E_NOINTERFACE if QI failed } // CStopLiteCtrl::XObjSafe::SetInterfaceSafetyOptions // Since we're always safe, this is a no-brainer--but we do check to make // sure the interface requested exists and that the options we're asked to // set exist and are set on (we don't support unsafe mode). HRESULT STDMETHODCALLTYPE CactivexdemoCtrl::XObjSafe::SetInterfaceSafetyOptions( REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions) { METHOD_PROLOGUE(CactivexdemoCtrl, ObjSafe) // does interface exist? IUnknown FAR* punkInterface; pThis->ExternalQueryInterface(&riid, (void * *)&punkInterface); if (punkInterface) { // interface exists punkInterface->Release(); // release it--just checking! } else { // interface doesn't exist return ResultFromScode(E_NOINTERFACE); } // can't set bits we don't support if (dwOptionSetMask & dwNotSupportedBits) { return ResultFromScode(E_FAIL); } // can't set bits we do support to zero dwEnabledOptions &= dwSupportedBits; // (we already know there are no extra bits in mask ) if ((dwOptionSetMask & dwEnabledOptions) != dwOptionSetMask) { return ResultFromScode(E_FAIL); } // don't need to change anything since we're always safe return ResultFromScode(S_OK); } /*IObjectSafety END*/
添加完成後從新生成便可。