MFC Activex 開發、ocx打包成cab、部署、測試、自動升級


        小小抱怨下:也許是MFC現在用的人少的緣故。在國內和國外都基本上找不到什么全的資料。特別是ocx打包成Cab時的安裝文件inf的編寫方面,國內基本上是copy,抄的還一知半解。查找個資源真心的累啊。現在將編寫步驟和遇到的問題以及問題的解決辦法記錄下來。有的資源是參考了別人的博文,有引用的地方將附上連接,再次感謝這些博主,如有侵權,請聯系本人,立即刪除。

一、MFC Activex 項目的構建

       此處使用的是:vs2015,操作按照圖片順序,沒有特別注意的地方不做文字注釋了。(不詳細的地方可以參考:https://blog.csdn.net/longhuahaha/article/details/8556964

  第一:新建項目

   

  

  

  

  

  

  activexdemo項目創建完成的目錄結構

  

 

  第二、先介紹四個文件

  activexdemo.cpp、activexdemoCtrl.cpp、activexdemoPropPage.cpp、activexdemo.idl

  (1) activexdemo.cpp文件中定義了DllRegisterServer和DllUnregisterServer,可以發現ActiveX的注冊和反組冊都與該類有關

   

  (2)activexdemoCtrl.cpp文件

           可以發現該頭文件中聲明了消息映射(讓ActiveX控件程序可以接受系統發送的事件通知,如窗體創建和關閉事件),調度映射(讓外部調用程序(包含ActiveX的容器)可以方便地訪           問ActiveX控件的屬性和方法),事件映射(讓ActiveX控件可以向外部調用程序(包含ActiveX的容器)發送事件通知)。也就是說對ActiveX控件的窗口操作都將在這個類中完成,包括                 ActiveX控件的創建,重繪,以及在此類中創建可視MFC窗體。

  

  (3)activexdemoPropPage.cpp:顯示ActiveX控件的屬性頁的

  (4)activexdemo.idl:對外接口定義文件

  

  第三、定義調度映射和事件映射方法,提供給外部調用者使用

  (1)通過類視圖進行定義:

  

  

  在_Dactivexdemo上鼠標右鍵:

  

  以添加對外接口方法BSTR initDvr(BSTR info, BSTR appKey, BSTR accessToken, LONG rowNum, FLOAT height);方法為例。BSTR為MFC中的數據類型。不懂的可以去百度了解。

  

  點擊下一步

  

  填寫完信息后點擊完成,外部就可以調用方法initDvr,同時ActiveX控件項目代碼的內部將會在三個文件中新增代碼:

  

  

  

  第四、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控件進行反注冊。

  

      第五、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的各節的詳細解釋請參考博文:https://www.cnblogs.com/xiangxinhouse/p/10392161.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包。

  第六、添加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,然后再次反注冊和注冊,進行測試。結果如下:

  

  

  第七、ocx更新:

  上面注冊的ocx在注冊表中沒有InstalledVersion這個項,需要在inf文件中添加。

  

  inf編輯添加InstalledVersion。如果不添加,可能會出現IE瀏覽器刷新后一直提示需要重復安裝Activex控件。

  

  inf添加了AddReg后的注冊表項:

  

  第八、關於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*/

  添加完成后重新生成即可。

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM