<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

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

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    源代碼下載:MyActiveX20081229.rar

    聲明:本文代碼基于CodeProject的文章《A Complete ActiveX Web Control Tutorial》修改而來,因此同樣遵循Code Project Open License (CPOL)

          在上一篇文章《COM組件開發實踐(七)---多線程ActiveX控件和自動調整ActiveX控件大小()》中介紹了ActiveX控件中使用多線程的基本需求,并提出了一個簡單的線程模型,但卻出現了意想不到的問題,本文將嘗試給出問題的一個可行的解法,并同時解決上文中提出的第二個問題。

          其實解決的思路也很簡單,一開始我也早就想到了的,就是使用讓子線程PostMessage來發出自定義的消息來通知主線程,特定的事件已經發生了,需求主線程去響應。這不是什么了不起的想法,但我對子線程PostMessage非常恐懼,因為以前的一個項目中就是這個問題導致了內存泄露,所以這個方案一開始就被我否定了。

          遍尋解決之道不可得時,只得在csdn的論壇上發貼求教高手了,具體的討論請參考這個帖子:

    http://topic.csdn.net/u/20081226/17/9bf0ae08-c54d-4934-b1b2-91baa27ff76e.html

    看到jameshooo(胡柏華)的回帖后,還是決定回到起點,嘗試用PostMessage這個方案。

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

    復制代碼#define WM_OPTSUCCESS WM_APP+101 //操作成功
    #define WM_OPTFAILED WM_APP+102    //操作失敗
    復制代碼

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

    復制代碼/////////////////////
    //回調函數
    /////////////////////////
    void CMyActiveXCtrl::OnSuccesful()
    {
    //操作成功
        this->PostMessage(WM_OPTSUCCESS,(WPARAM)NULL,(LPARAM)NULL);
    }

    void CMyActiveXCtrl::OnFailed()
    {
    //操作失敗
        this->PostMessage(WM_OPTFAILED,(WPARAM)NULL,(LPARAM)NULL);
    }
    復制代碼

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

    復制代碼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);   
    }
    復制代碼

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

    復制代碼
    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;
    }
    復制代碼

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

    復制代碼void CMyActiveXCtrl::OnClose(DWORD dwSaveOption)
    {
        pThread.Stop(
    true);//強行關閉工作線程
        COMRELEASE(pWebBrowser);
        COMRELEASE(pHTMLDocument);
        COleControl::OnClose(dwSaveOption);
    }
    復制代碼

         到此為止,一個多線程的ActiveX控件就誕生了。這里是不會發生以前我遇到的內存泄露的,因為情況不同了,只是在回調函數中簡單的post一個message,并沒有new一個內存區域并將這塊內存作為參數post給主線程,后面這種情況是可能會內存泄露的。

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

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

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

     

    RFID設備管理軟件

         一種是特殊模式,

    RFID設備管理軟件 

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

    復制代碼<PARAM NAME="IsSpecial" VALUE="TRUE"> 復制代碼

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

    復制代碼CString m_bIsSpecial;//是否是"特殊"頁面 復制代碼

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

    復制代碼
    void CMyActiveXCtrl::DoPropExchange(CPropExchange* pPX)
    {
        ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
        COleControl::DoPropExchange(pPX);

        PX_String(pPX,   _T(
    "IsSpecial"),   m_bIsSpecial); //讀取外部設置的參數
    }
    復制代碼

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

    復制代碼public:
        CMyDlgTwo m_dlgSpecial;
    //特殊模式
        CMyDlgThree m_dlgCommon;//普通模式
    復制代碼

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

    復制代碼int CMyActiveXCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        
    if (COleControl::OnCreate(lpCreateStruct) == -1)
            
    return -1;

        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);
            
    //設置控件的大小
            newRc.left = 0
            newRc.top 
    = 0
            newRc.right 
    = 200
            newRc.bottom 
    = 200
        }
        
    this->m_pInPlaceSite->OnPosRectChange(&newRc);
        
    return 0;
    }

    void CMyActiveXCtrl::OnDraw(
                CDC
    * pdc, const CRect& rcBounds, const CRect& rcInvalid)
    {
        
    if (!pdc)
            
    return;
        
    if(m_bIsSpecial.Compare(_T(""))==0)
        {
    //沒設置參數,"普通“模式
            this->m_dlgCommon.MoveWindow(rcBounds,TRUE);
        }
        
    else
        {
    //設置了參數,”特殊“模式
            this->m_dlgSpecial.MoveWindow(rcBounds,TRUE);
        }
    }
    復制代碼

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

     

    作者:phinecos(洞庭散人)
    出處:http://phinecos.cnblogs.com/
    本文版權歸作者和博客園共有,歡迎轉載,但請保留此段聲明,并在文章頁面明顯位置給出原文連接。

    作者:洞庭散人

    出處:http://phinecos.cnblogs.com/    

    本博客遵從Creative Commons Attribution 3.0 License,若用于非商業目的,您可以自由轉載,但請保留原作者信息和文章鏈接URL。RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全