其實解決的思路也很簡單,一開始我也早就想到了的,就是使用讓子線程PostMessage來發出自定義的消息來通知主線程,特定的事件已經發生了,需求主線程去響應。這不是什麼了不起的想法,但我對子線程PostMessage非常恐懼,因為以前的一個項目中就是這個問題導緻了記憶體洩露,是以這個方案一開始就被我否定了。
遍尋解決之道不可得時,隻得在csdn的論壇上發貼求教高手了,具體的讨論請參考這個文章:
<a href="http://topic.csdn.net/u/20081226/17/9bf0ae08-c54d-4934-b1b2-91baa27ff76e.html">http://topic.csdn.net/u/20081226/17/9bf0ae08-c54d-4934-b1b2-91baa27ff76e.html</a>
看到jameshooo(胡柏華)的回帖後,還是決定回到起點,嘗試用PostMessage這個方案。
首先自定義兩個事件,分别表示操作成功和操作失敗
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
#define WM_OPTSUCCESS WM_APP+101 //操作成功
#define WM_OPTFAILED WM_APP+102 //操作失敗
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
然後回調函數中就變得非常簡單,隻需要post對應的事件即可。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
/////////////////////
//回調函數
/////////////////////////
void CMyActiveXCtrl::OnSuccesful()
{//操作成功
this->PostMessage(WM_OPTSUCCESS,(WPARAM)NULL,(LPARAM)NULL);
}
void CMyActiveXCtrl::OnFailed()
{//操作失敗
this->PostMessage(WM_OPTFAILED,(WPARAM)NULL,(LPARAM)NULL);
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
再重載消息處理函數WindowProc,在其中調用外部的JavaScript函數或者Fire出外部頁面可以響應的事件。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
LRESULT CMyActiveXCtrl::WindowProc(UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_OPTSUCCESS:
{//操作成功,通知外部頁面
CString strOnLoaded("OnLoaded");
this->CallJScript(strOnLoaded);
return 0;
}
case WM_OPTFAILED:
{//操作失敗,通知外部頁面
//這裡不寫了,同上面
}
return COleControl::WindowProc(msg,wParam,lParam);
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
在OnCreate函數中加入啟動工作線程代碼:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
int CMyActiveXCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
if (COleControl::OnCreate(lpCreateStruct) == -1)
return -1;
m_MainDialog.Create(IDD_MAINDIALOG, this);
pThread.SetICallBack(this);//設定主線程回調函數
pThread.Start();//啟動工作線程
return 0;
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
重載掉OnClose函數,在其中加入關閉工作線程的代碼:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
void CMyActiveXCtrl::OnClose(DWORD dwSaveOption)
pThread.Stop(true);//強行關閉工作線程
COMRELEASE(pWebBrowser);
COMRELEASE(pHTMLDocument);
COleControl::OnClose(dwSaveOption);
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
到此為止,一個多線程的ActiveX控件就誕生了。這裡是不會發生以前我遇到的記憶體洩露的,因為情況不同了,隻是在回調函數中簡單的post一個message,并沒有new一個記憶體區域并将這塊記憶體作為參數post給主線程,後面這種情況是可能會記憶體洩露的。
Ok,下面來考慮第二個問題,先簡單介紹下具體需求:就是一個AcitveX控件會用到不同的頁面中,每個頁面對這個控件的需求也不同,也就要求在兩個不同的頁面中,控件顯示的大小也不同。
jameshooo(胡柏華) 回帖說:“改變控件大小要通知容器,由容器再反過來通知控件改變大小,不然沒有任何效果。調用IOleInPlaceSite::OnPosRectChange即可”。是以就根據這個來嘗試提出一個解決方案來。
假設有兩種模式的控件,一種是“普通”模式, 如下圖所示:
一種是“特殊”模式,
為了差別開兩者,就考慮在web頁面中通過設定參數的方式來通知ActiveX控件,對于不同的模式填充不同的對話框就可以了。我們在web頁面中控件部分加入如下參數:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
<PARAM NAME="IsSpecial" VALUE="TRUE">
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
相應的在CMyActiveXCtrl類中加入一個變量,這裡為簡單起見,選擇了類型為CString型,主要是為了傳參數友善。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
CString m_bIsSpecial;//是否是"特殊"頁面
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
Web頁面傳入的參數值在下面這個函數中讀取:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
void CMyActiveXCtrl::DoPropExchange(CPropExchange* pPX)
ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
COleControl::DoPropExchange(pPX);
PX_String(pPX, _T("IsSpecial"), m_bIsSpecial); //讀取外部設定的參數
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
為了供控件選擇,這裡提供了兩種模式的對話框:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
public:
CMyDlgTwo m_dlgSpecial;//特殊模式
CMyDlgThree m_dlgCommon;//普通模式
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
然後在建立和繪制對話框時,通過檢測參數是否為空就知道待建立的對話框類型到底是“普通“還是”特殊“了。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
CRect newRc;
if(m_bIsSpecial.Compare(_T(""))==0)
{//沒設定參數,"普通“模式
this->m_dlgCommon.Create(IDD_DIALOG3,this);
//設定控件的大小
newRc.left = 0;
newRc.top = 0;
newRc.right = 200;
newRc.bottom = 200;
else
{//設定了參數,”特殊“模式
this->m_dlgSpecial.Create(IDD_DIALOG2,this);
this->m_pInPlaceSite->OnPosRectChange(&newRc);
void CMyActiveXCtrl::OnDraw(
CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
if (!pdc)
return;
this->m_dlgCommon.MoveWindow(rcBounds,TRUE);
this->m_dlgSpecial.MoveWindow(rcBounds,TRUE);
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
這種方法對于我目前的需求剛好是滿足的,但也許還有其他更好的方法,也希望有知道的能貢獻出來,一起學習下。
本文版權歸作者和部落格園共有,歡迎轉載,但請保留此段聲明,并在文章頁面明顯位置給出原文連接配接。