天天看點

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

      其實解決的思路也很簡單,一開始我也早就想到了的,就是使用讓子線程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這個方案。

首先自定義兩個事件,分别表示操作成功和操作失敗

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

#define WM_OPTSUCCESS WM_APP+101 //操作成功

#define WM_OPTFAILED WM_APP+102    //操作失敗

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

     然後回調函數中就變得非常簡單,隻需要post對應的事件即可。

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

/////////////////////

//回調函數

/////////////////////////

void CMyActiveXCtrl::OnSuccesful()

{//操作成功

    this-&gt;PostMessage(WM_OPTSUCCESS,(WPARAM)NULL,(LPARAM)NULL);

}

void CMyActiveXCtrl::OnFailed()

{//操作失敗

    this-&gt;PostMessage(WM_OPTFAILED,(WPARAM)NULL,(LPARAM)NULL);

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

     再重載消息處理函數WindowProc,在其中調用外部的JavaScript函數或者Fire出外部頁面可以響應的事件。

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

LRESULT CMyActiveXCtrl::WindowProc(UINT msg, WPARAM wParam, LPARAM lParam)

{

    switch (msg)

    {

    case WM_OPTSUCCESS:

        {//操作成功,通知外部頁面

            CString strOnLoaded("OnLoaded");

            this-&gt;CallJScript(strOnLoaded);

            return 0;

        }

    case WM_OPTFAILED:

        {//操作失敗,通知外部頁面

            //這裡不寫了,同上面

    }

    return   COleControl::WindowProc(msg,wParam,lParam);   

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

     在OnCreate函數中加入啟動工作線程代碼:

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

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;

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

     重載掉OnClose函數,在其中加入關閉工作線程的代碼:

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

void CMyActiveXCtrl::OnClose(DWORD dwSaveOption)

    pThread.Stop(true);//強行關閉工作線程

    COMRELEASE(pWebBrowser);

    COMRELEASE(pHTMLDocument);

    COleControl::OnClose(dwSaveOption);

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

     到此為止,一個多線程的ActiveX控件就誕生了。這裡是不會發生以前我遇到的記憶體洩露的,因為情況不同了,隻是在回調函數中簡單的post一個message,并沒有new一個記憶體區域并将這塊記憶體作為參數post給主線程,後面這種情況是可能會記憶體洩露的。

Ok,下面來考慮第二個問題,先簡單介紹下具體需求:就是一個AcitveX控件會用到不同的頁面中,每個頁面對這個控件的需求也不同,也就要求在兩個不同的頁面中,控件顯示的大小也不同。

      jameshooo(胡柏華) 回帖說:“改變控件大小要通知容器,由容器再反過來通知控件改變大小,不然沒有任何效果。調用IOleInPlaceSite::OnPosRectChange即可”。是以就根據這個來嘗試提出一個解決方案來。

假設有兩種模式的控件,一種是“普通”模式, 如下圖所示:

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

     一種是“特殊”模式,

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

     為了差別開兩者,就考慮在web頁面中通過設定參數的方式來通知ActiveX控件,對于不同的模式填充不同的對話框就可以了。我們在web頁面中控件部分加入如下參數:

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

&lt;PARAM NAME="IsSpecial" VALUE="TRUE"&gt;

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

        相應的在CMyActiveXCtrl類中加入一個變量,這裡為簡單起見,選擇了類型為CString型,主要是為了傳參數友善。

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

CString m_bIsSpecial;//是否是"特殊"頁面

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

     Web頁面傳入的參數值在下面這個函數中讀取:

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

void CMyActiveXCtrl::DoPropExchange(CPropExchange* pPX)

    ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));

    COleControl::DoPropExchange(pPX);

    PX_String(pPX,   _T("IsSpecial"),   m_bIsSpecial); //讀取外部設定的參數

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

     為了供控件選擇,這裡提供了兩種模式的對話框:

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

public:

    CMyDlgTwo m_dlgSpecial;//特殊模式

    CMyDlgThree m_dlgCommon;//普通模式

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

     然後在建立和繪制對話框時,通過檢測參數是否為空就知道待建立的對話框類型到底是“普通“還是”特殊“了。

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

    CRect newRc; 

    if(m_bIsSpecial.Compare(_T(""))==0)

    {//沒設定參數,"普通“模式

        this-&gt;m_dlgCommon.Create(IDD_DIALOG3,this);

        //設定控件的大小

        newRc.left = 0; 

        newRc.top = 0; 

        newRc.right = 200; 

        newRc.bottom = 200; 

    else

    {//設定了參數,”特殊“模式

        this-&gt;m_dlgSpecial.Create(IDD_DIALOG2,this);

    this-&gt;m_pInPlaceSite-&gt;OnPosRectChange(&amp;newRc);

void CMyActiveXCtrl::OnDraw(

            CDC* pdc, const CRect&amp; rcBounds, const CRect&amp; rcInvalid)

    if (!pdc)

        return;

        this-&gt;m_dlgCommon.MoveWindow(rcBounds,TRUE);

        this-&gt;m_dlgSpecial.MoveWindow(rcBounds,TRUE);

COM元件開發實踐(八)---多線程ActiveX控件和自動調整ActiveX控件大小(下)

        這種方法對于我目前的需求剛好是滿足的,但也許還有其他更好的方法,也希望有知道的能貢獻出來,一起學習下。

本文版權歸作者和部落格園共有,歡迎轉載,但請保留此段聲明,并在文章頁面明顯位置給出原文連接配接。

繼續閱讀