• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 67  文章 - 171  trackbacks - 0
            <2014年8月>
            272829303112
            3456789
            10111213141516
            17181920212223
            24252627282930
            31123456

            常用鏈接

            留言簿(10)

            隨筆分類

            隨筆檔案

            連接資料

            最新隨筆

            搜索

            •  

            最新隨筆

            最新評論

            這篇文章使用了以下技術:

            C++, MFC, .NET Framework, Windows Presentation Foundation

             

            盡管Microsoft .NET Framework在大約五年前就首次公布了,而且2.0版本最近也已經發布了,但是許多C++應用程序仍舊是純的非托管代碼。然而C++的開發人員對.NET Framework的興趣正在快速地增長。并且,許多未來的Windows® API將基于.NET Framework。當然,這對于WinFX®的組件來說也是正確的,包括Windows Presentation FoundationWindows Communication Foundation,和Windows Workflow Foundation

            而且,許多C++開發人員愿意使用本機API,而不是在現存的API上進行包裝。包裝往往被認為是有bug的、慢的以及不靈活的。除此之外,要把像WinFX一樣的大量API映射成為供本機代碼使用的API,確實困難。

            在大多數情況下,為C++應用程序擴展.NET Framework特性比大多數開發人員想象的要簡單。Visual C++®包含了一種被稱作是C++ Interop的特性,有時簡稱為IJW,或“It Just Works”。 使用本特性可以把基于.NET的代碼無縫地集成到已經存在的C++源代碼中。

            C++ Interop基于兩個主要的特性。首先,你能使用C++編譯器的/clr開關將已經存在的C++代碼編譯成Microsoft®中間語言(MSIL),從而你的代碼可以使用.NET特性,如垃圾回收、沙箱安全以及大量.NET Framework基類庫中的類型。

            另一個特性是混合模式,它也是同等重要的。它是指托管代碼和非托管代碼的聯合。當把C++代碼編譯成MSIL時,編譯器創建了包含MSIL代碼的托管對象文件,而不是包含本機匯編代碼的普通的非托管對象文件。連接器能把托管對象文件和非托管對象文件同時作為輸入。當連接器檢測到至少有一個托管輸入時,它創建一個同時包含有托管代碼和非托管代碼的.NET程序集(assembly)。這是它被稱為混合模式的原因(見1)。這個特性對于性能優化尤其重要,因為它允許你最大程度地減少在托管空間和非托管空間的轉換次數。

             

             
            1 MTS

             

            C++ Interop是你的朋友

            我的經驗表明,C++ Interop是非常可靠的,盡管它有一些限制,但還是值得把它加入到你的開發工具箱中。要理解這一特性是如何工作的,你應當認識到C++ Interop.NET Framework的一個設計特性。作為.NET Framework基礎規格的通用語言基礎架構(CLI),已經支持了這一特性。事實上,CLI的一些方面被定義,僅僅是因為C++ Interop需要它們。

            例如,托管元數據支持全局函數。然而C#和大多數面向.NET的其他語言要求所有方法要存在于類的范圍內。這一特性的存在是因為應當被映射成基于.NET代碼的C++代碼可以包含全局函數,為了把C++代碼映射成托管代碼,元數據需要一個同等的概念。

            在設計上,MSIL指令集已經支持C++ Interop。為了把C++代碼映射為MSIL代碼,MSIL必須支持所有公共數據操作運算符,如布爾、算術以及符點運算符。MSIL也支持對虛擬內存基于指針的存取。這一特性是在托管代碼中使用本地類型的關鍵。如果你的C++代碼要存取一個本地對象的一個字段,C++/CLI編譯器會生成MSIL代碼,把本地對象的地址壓到堆棧上,在其上加上字段的偏移,并使用返回地址來存取字段。所有這些成為可能是因為MSIL指令集有通過地址來存取虛擬內存地址的操作。

            另一種IL語言的C++特定的特性是CALLI指令。它可被用于通過函數指針調用本地函數。這個特性被用于調用本地類型的虛函數。這很重要,因為COM接口是帶有虛函數的本地類型。這種COM互操作的方法,與用于其他語言的其他COM互操作技術相比,具有許多優點。

            最后值得一提的是,對使用.NET的所有開發人員最明顯的設計影響是組件的文件格式。Java定義了自己的文件格式(.class文件),然而.NET Framework使用標準PE文件格式。因此,基于.NET的組件有很合適的文件擴展DLLEXEPE文件仍被使用的事實對于支持混合模式的程序集來說是至關重要的。

             

            何時使用C++ Interop

            要評估C++ Interop是否適用于你的項目,你應當了解這個特性在生成你的項目時所帶來的影響,對開始者來說,即編譯器設置,同時,也應當了解它對于生成過程的輸出結果的影響。如果使用/clr選項進行編譯,代碼嚴格依賴C運行時庫(CRT)的多線程DLL版本。這意味著項目中的所有文件,包括那些不使用/clr編譯的文件,必須使用CRT的多線程DLL版本。這對MFC項目同樣重要。靜態MFC庫依賴靜態CRT庫,它不兼容/clr編譯。因此,你必須確認你的MFC項目連接到MFCDLL版本。

            這兒還有一些關于執行時間的話題。初始化CLR占用一定量的時間,JIT編譯也有一些附加時間。因此,你也許感覺啟動時間稍微變長。然而,對大多數項目而言,這應當不是一個大的問題。

            由托管到非托管切換的方法調用,比通常的方法調用花費的時間更長。我已提到過,你可以通過判定你的應用的某些特定部分將被編譯成托管代碼,來顯著地減少托管和非托管代碼之間的切換。調用轉換__clrcall是另一種可以顯著地減少切換次數的重要優化特性,但這一特性超出本文的范圍。

            在大多數情形下,即時(JIT)編譯代碼本身并不是性能顯著下降的原因。事實上,JIT編譯器可以完成一些優化,而C++編譯器和連接器卻不可能完成。例如,JIT編譯器可以針對目標機器的處理器架構優化代碼。與C++編譯器相反,JIT編譯器提供組件間內聯。這可能是一個非常有效的優化,因為編譯成帶有組件間內聯的代碼可以用于未來的優化。

            除了在這兒提到的話題外,還有一些其他相關的領域,我將不再詳細地討論。它們中的大部分可以通過正確地修改編譯器和連接器設置,很容易地被解決。最佳的編譯器設置并不總是直截了當的。一些設置打開了對C++ Interop編譯強制的特性,而一些其他的設置關閉了與/clr編譯不兼容的,或者已經被Microsoft中間語言以另一種方法解決了的特性。

             

            MFC應用中的Windows窗體控件

            所有使用/clr選項編譯的源文件可以使用.NET Framework基類庫中的類型。你可以像你一直使用它們那樣,來使用大部分的基類庫。有一些情況需要特別注意。在MFC應用中集成Windows窗體控件就是一個例子。

            你不能在需要CWnd*時傳遞System::Windows::Forms::Control^。然而,Windows窗體APIMFC共享公共的基礎:好的古老的User32.dll。這兩種API都提供了到HWNDs的一些后門。MFCCWnd類提供一個到HWND的轉換操作符,而Windows窗體控件類在命名空間System::Windows::Forms中實現了IWin32Window接口,以暴露出窗口句柄:

            public interface IWin32Window {

             property IntPtr Handle {

                IntPtr get ();

             }

            };

            然而,從一個Window對象中獲得窗口句柄通常是不夠的。MFC提供一些類來支持在不同場景下處理Windows窗體控件。這些類被定義在afxwinforms.h中。

            這些類中最重要的是CWinFormsControl,它被定義在命名空間Microsoft::VisualC::MFC中。這個類允許在一個MFC對話框或CDialog派生類中宿主一個Windows窗體控件。它是帶有一個模板參數的模板類,參數被用于傳遞要宿主的Windows窗體的類型。類型是要稍后實例化的具體類型,或者是具體類型的基類。CWinFormsControl模板很簡單。它只有兩個有趣的特性:它繼承于CWnd,提供了一個自解釋方法CreateManagedControl的幾種重載形式。

            如果你想在MFC對話框或CDialog派生類中宿主一個Windows窗體控件,在你的類中定義一個類型為CWinFormsControl<TWinFormsCtrl>的成員變量,并選擇一種CreateManagedControl的重載形式。如果你實現一個CDialog派生類,創建托管控件的好的候選是OnInitDialog。對大多數其他情形,OnCreateWM_CREATE消息處理)是最好的選擇。對于對話框類而言,有一種重載形式尤其有趣。這種重載方式期望在對話框資源中加入一個靜態控件作為占位符。放置靜態控件,以便它有Windows窗體控件應當有的位置和大小,并且賦給它一個唯一的ID,如4所示。要實例化被宿主的控件,如2所示調用CreateManagedControl。此外,你甚至可以使用對話框數據交換(DDX)的一個特別變種,如3所示。

             


            4
            使用ActiveX控件

            注意,在MFC應用中宿主Windows窗體控件的方式,使用了另一種基于Windows窗體和MFC的技術:ActiveX控件。如5列表所示,System::Windows::Forms::Control實現了一些接口,它們對于OLEActiveX控件熟悉的老手們來說很熟悉。在CreateManagedControl中,Windows窗體控件通過gcnew操作符被實例化,并像一個普通ActiveX控件一樣被就地激活。

            還要注意,CWinFormsControl重載了->操作符,返回被宿主的控件。這允許你通過簡單的賦值來設置按鈕的Text屬性:

            m_wfBtn.Text = "Click me!";

            這種處理方式不如在屬性窗口中修改控件屬性那樣簡潔,但是如果你適應了現存的有限的設計器支持,Windows窗體控制的世界將向你可信的老的MFC對話框開放。

             

            處理控件事件

            這兒還要討論一些其他問題。到目前為止,按鈕的單擊事件還沒有被處理。因為你有一個像ActiveX控件一樣被宿主的Windows窗體控件,處理事件有兩種選擇:由ActiveX控件提供的連接點方式,和Windows窗體控件的事件成員方式。如果Windows窗體控件準備支持基于COM的事件,連接點方案才成為可能。大多數Windows窗體控件并不符合這種情形,所以以.NET方式處理事件是唯一的方法。托管類中的事件是一種特別的類型成員,允許事件處理程序委托(event handler delegate)的注冊和注銷。以下的代碼行展示了如何注冊按鈕的單擊事件:

            m_wfBtn.Click +=<單擊事件的一個事件處理程序委托>

            要提供這樣一個委托,需要如下語法的一個函數:

            void EventHandler(Object^ sender, EventArgs^ e);

            很不幸,在CDialog派生類中實現這樣一個方法還不夠。

            委托目標函數必須是托管類的成員函數,CDialog派生類是一個本地類。Visual C++提供了一個頭文件,\Msclr\Event.h,針對這個問題給出了通用解決方案。當你想用本地C++類的方法來處理.NET事件時,可以使用頭文件中的定義。正如我稍后要討論的,當你要集成Windows Presentation FoundationVisuals特性時,同樣可以使用這一頭文件。因為這一頭文件在如此多的不同的情形下是有用的,所以深入地討論它提供的解決方案是有意義的。

            為了處理Windows窗體控件的事件,你可以實現包含消息處理程序的一個托管類。C++ Interop允許你以優雅的方式去處理,因為托管類可以被嵌入到CDialog派生類中。

            class CMyDialog : public CDialog {

                ref class nested_managed_class {

                    void OnWFBtnClick(Object^ sender, EventArgs^ e) {

                        // 在這兒處理按鈕單擊事件

                    }

                };

                // 其他成員

            };

            最便利的處理按鈕單擊事件的方法是,把方法調用移交給CDialog派生類的一個成員函數。最終處理單擊事件的方法,可以很容易地存取派生類的其他成員,就像你期望事件處理程序工作的那樣。包含委托目標的托管類最終成為了一個簡單的代理類型。盡管這樣一個代理類型和它的代理事件處理程序可以由定義在Event.h中的宏來創制,但是讓我們首先看看如何進行手工定義(見6)。

            如你所見,委托代理有一個帶有CMyDialog*參數的構造函數。要把方法調用移交給CDialog派生類,這樣一個構造函數是必要的。這一委托代理類型可以用于本對話框類中的所有Windows窗體控件的所有事件處理程序。

            因為本地類中不能有指向垃圾回收對象的句柄作為字段,所以在派生類中增加一個delegate_proxy_type的成員變量是不可能的。使用gcroot模板,你可以繞過這一限制。因此,一個類型為gcroot<delegate_proxy_type>的成員變量是必須的。然而,還有一個問題:委托代理類型的gcrooted引用是如何被正確地初始化的?當需要delegate_proxy_type的句柄時,調用一個單獨的方法來處理。

            運用6的代碼,如下例所示,委托能被容易地注冊:

            virtual BOOL OnInitDialog() {

                CDialog::OnInitDialog();

             

                this->m_wfBtn->Click +=

                    gcnew System::EventHandler(get_proxy(this),

                    &delegate_proxy_type::OnWFBtnClick);

             

                return TRUE;

            }

            寫所有這些代碼的工作量非常大,而這些僅僅是為了在CDialog派生類中處理Windows窗體控件的事件。Event.h包含了宏和模板,使得你可以用很少的代碼行完成同樣的甚至更多的功能,如7所示。

            每個新版本的MFC至少有一個新的映射(map)。如你所見,目前版本引入了委托映射。宏BEGIN_DELEGATE_MAP定義了包含有委托目標的delegate_proxy_type。每一個EVENT_DELEGATE_ENTRY行在托管類中增加了一個目標方法。END_DELEGATE_MAP只是結束了托管類。最后,MAKE_DELEGATE實例化一個指向delegate_proxy_type的目標方法的委托。實際上,這些宏做的事情比我剛才討論的還要更多。它們甚至為以下場景做好了準備,在托管類發生的事件要被發送給一個不再存在的本地對象。

             

            作為對話框的控件

            另一個簡單但有效的助手是CWinFormsDialog模板。你可以使用它以模態或非模態對話框的形式來展示一個Windows窗體控件。這個類相當簡單。它擴展CDialog來提供MFC對話框的標準行為。

            除此以外,它使用一個CWinFormsControl成員變量來宿主Windows窗體控件,用被宿主控件的Text屬性值來初始化對話框的標題,設置對話框的初始大小,以便控件恰好嵌入其中,并確保當父窗口大小在改變時,調整被宿主控件的大小。

            下面的一行代碼實例化一個宿主YourWinFormsDlgControl的臨時對話框,并以一個模態對話框形式顯示它:

            CWinFormsDialog<YourWinFormsDlgControl>().DoModal();

            然而,你應當避免這樣來使用,因為這樣無法使用DoModal的對話框返回值。對于更實際的情況,考慮從CWinFormsDialog<YourWinFormsDlgControl>中派生你自己的類。這允許你重載OnInitDialog,設置被嵌入的Windows窗體控件的屬性,或處理被宿主控件的事件。我之前描述的Event.h中的宏在這種情況下也是有用的。要獲得更多信息,參見msdn2.microsoft.com/ahdd1h97.htm

            Windows窗體視圖

            最后,你可以以視圖的方式宿主Windows窗體控件。CWinFormsView是這種情形下你要的小助手。不像CWinFormsDialog一樣,它并不是一個模板類。然而,也有很多相似之處。它們都把實際的控件宿主留到了CWinFormsControl模板中,并且它們都處理被宿主控件的大小調整。

            為了用一個MFC對話框來宿主Windows窗體控件,你必須從CWinFormsView中繼承你的視圖類。以下代碼展示了一個簡單的基于CWinFormsView的視圖類的聲明:

            class CMyWinFormsBasedView : public CWinFormsView

            {

                CMyWinFormsBasedView ();

                DECLARE_DYNCREATE(CMyWinFormsBasedView)

            };

            如果你的視圖類是由向導生成的,你應當確保不僅在你的視圖類定義的基類列表中,而且在它的實現中,改換成CWinFormsView。你可能要改變宏的參數,如IMPLEMENT_DYNAMICBEGIN_MESSAGE_MAP宏。要實例化被宿主的Windows窗體控件,CWinFormsView(你的視圖基類)的構造函數得到一個指向Windows窗體控件的System::Type對象的句柄。視圖類的實現也非常簡單,如下所示:

            IMPLEMENT_DYNCREATE(CMyWinFormsBasedView, CWinFormsView)

             

            CMyWinFormsBasedView:: CMyWinFormsBasedView ()

                : CWinFormsView(WinFormsViewControl::typeid) {}

            初看起來,這段代碼對于實際情況來說太簡單,但是在一些情況下,這確實就是你所需要的全部。視圖類充當了位于視圖控件中的真實實現的簡單代理。

            一些視圖的實現重載了MFC CView基類中的虛函數。要讓本地視圖充當一個簡單的代理,應當在本地視圖中重載這些方法,并把這些調用移交給視圖中Windows窗體控件的對等方法。對CView中的三個最重要的重載來說,基類CWinFormsView已經實現了這樣的移交。這三個方法是OnInitialUpdateOnUpdate以及OnActivateView。傳遞基于定義在Mfcmifc80.dll程序集中的托管接口Microsoft::VisualC::MFC::IView。為了重載這些方法,在視圖的Windows窗體類中實現這一接口,如8所示。

            除了重載虛函數以外,視圖還實現了命令處理程序。在本地視圖類中實現一個命令處理程序并把它傳遞給Windows窗體控件是可能的,但是因為這是一種常見的場景,所以MFC提供了一個更為便利的解決方案。在這種場景下,Mfcmifc80.dll程序集包含了更多的托管助手類型。要從MFC的命令傳送基礎結構中接收命令消息,Windows窗體控件必須實現Microsoft::VisualC::MFC::ICommandTarget接口:

            interface class ICommandTarget

            {

                void Initialize(ICommandSource^ commandSource);

            };

            當實現ICommandTarget的視圖被創建時,在那個視圖上,ICommandTarget::Initialize被調用,一個新命令源對象的句柄被當作參數傳遞。這個參數的類型是ICommandSource^。參數所指的對象是一個許多處理程序的容器。這些處理程序對于MFC開發人員來說,聽起來應當很熟悉:它們是當一個命令發出時被調用的命令處理程序;控制控件的UI是否使能、選中,或用單選按鈕裝飾,以及在命令UI中顯示什么樣的文字的命令UI處理程序。

            要注冊一個處理程序,像AddCommandHandlerAddCommandUIHandler一樣的方法,可以在命令源上被調用。這些方法期望兩個參數:指代命令ID的無符號整數,和被用于傳遞控件處理程序函數的委托。因為命令處理程序和命令UI處理程序有著不同的簽名,在命名空間Microsoft::VisualC::MFC中定義了兩個不同的委托類型:

            delegate void CommandHandler(unsigned int);

            delegate void CommandUIHandler(unsigned int,

                Microsoft::VisualC::MFC::ICommandUI^);

            9展示了如何為ID_EDIT_PASTE命令注冊一個命令處理程序。

            當視圖要處理一個命令時,委托被用于調用一個視圖的成員函數。命令ID被作為參數來傳遞。如果每個命令有自己私有的處理程序函數,這個參數并不重要,但是一個簡單的方法可以被用于多個命令的處理程序函數。AddCommand[UI]RangeHandler允許你為多個命令注冊一個委托。

            命令UI處理程序委托還有一個類型為ICommandUI^的參數。使用這個參數傳遞的句柄是MFC CCmdUI類的包裝器,它允許你控制如菜單項和工具條按鈕等界面元素的表現和可用性。

            除了在ICommandSource::Initialize中增加命令處理程序外,在Windows窗體控件的成員變量中存儲ICommandTarget句柄也是很有用的。它給你提供了以后增加和移除命令處理程序的選擇,你甚至可以通過ICommandTarget::SendMessageICommandTarget::PostMessage來同步或異步發出命令事件。

             

             

            通向Avalon之橋

            因為Windows Presentation Foundation還沒有最終發布,當前的MFC版本并沒有在CWndsCDialogs中集成Windows Presentation FoundationVisuals提供助手類和模板。然而,這并不意味著在MFC應用中集成Visuals是不可能的。事實上,即使沒有這些小助手類,仍然只需要幾行代碼就能在CWndCDialog中宿主一個Visual

            這種集成的關鍵特性來自于Windows Presentation Foundation自身。Windows.PresentationCore.dll程序集提供了一個強有力的類HwndSource,它位于命名空間System::Windows::Interop中。這個類提供了HWNDVisual之間的橋。要宿主的USER32窗口對象看來像一個有通常HWND的子窗口。使用它的RootVisual屬性,你可以進入Windows Presentation Foundation的新世界。(注意,這兒的信息基于Windows Presentation Foundation的一個預發布版本,也許在最終發布時會改變。)

            HwndSource構造函數期望HwndSourceParameters的值類型作為參數。如10所示,這一值類型包含了與調用Win32函數CreateWindowEx所傳遞參數相似的信息。11展示了在OnInitDialog實現中如何使用HwndSource

             

            總結

            通過使用C++ Interop,托管代碼可以被無縫地集成到現存的C++源代碼中。集成是Visual C++本來就具有的、被支持的特性,對Windows窗體的MFC支持可以被認為是對此強有力的證據。為了簡化這種集成,提供了幾種助手類和模板。集成層并不復雜,也不難于使用。

            還有一件事情,是把這些特性無縫地集成到Visual Studio的向導中。在大多數的場景中,因為很多實現將被遺留到被宿主的Windows窗體控件中,所以這并不是一個大的問題,而Windows窗體控件在Visual Studio中得到了很好的支持。當Windows Presentation Foundation發布時,為了在MFC應用中集成Visuals,提供對等支持的可能性是很大的。即使沒有這種支持,在MFC應用中宿主Visuals仍然是很容易的。

             

            Marcus Heege works as a course author and trainer for DevelopMentor and provides consulting for different IT companies. He regularly posts his thoughts about C++/CLI and .NET in his blog at www.heege.net.


            From the May 2006 issue of MSDN Magazine.

             

            2 創建一個被宿主控件

            using Microsoft::VisualC::MFC;

            using System::Windows::Forms;

             

            class CMyDialog : public CDialog

            {

            public:

                CMyDialog() : CDialog(CMyDialog::IDD, NULL) {}

             

                enum { IDD = IDD_MYDIALOG };

             

            private:

                CWinFormsControl<Button> m_wfBtn;

             

            public:

                BOOL OnInitDialog() {

                    CDialog::OnInitDialog();

             

                    return this->m_wfBtn.CreateManagedControl(

                        WS_VISIBLE | WS_CHILD, IDC_WFBTN, this));

                }

            }

             

            3 宿主一個有對話框數據交換(DDX)的控件

            using Microsoft::VisualC::MFC;

            using System::Windows::Forms;

             

            class CMyDialog : public CDialog

            {

            public:

                CMyDialog(CWnd* pParent = NULL): CDialog(CMyDialog::IDD, pParent) {}

             

                enum { IDD = IDD_MYDIALOG };

             

            private:

                CWinFormsControl<Button> m_wfBtn;

             

            protected:

                virtual void DoDataExchange(CDataExchange* pDX) {

                    DDX_ManagedControl(pDX, IDC_WFBTN, this->m_wfBtn);

                }

            };

             

             

            5 接口

            System::Windows::Forms::Control

            IOleObject

            IOleControl

            IOleInPlaceObject

            IOleInPlaceActiveObject

            IOleWindow

            IOleViewObject

            IOleViewObject2

            IPersist

            IPersistStreamInit

            IPersistPropertyBag

            IPersistStorage

            IQuickActivate

             

            6 CMyDialog

            class CMyDialog : public CDialog

            {

            public:

                ref class delegate_proxy_type;

                gcroot<delegate_proxy_type^> m_gc_managed_native_delegate_proxy;

                delegate_proxy_type^ get_proxy(CMyDialog* pNativeTarget) {

                    if((delegate_proxy_type^)m_gc_managed_native_delegate_proxy ==

                        nullptr)

                    {

                        m_gc_managed_native_delegate_proxy =

                            gcnew delegate_proxy_type(pNativeTarget);

                    }

                    return (delegate_proxy_type^)m_gc_managed_native_delegate_proxy;

                }

             

                ref class delegate_proxy_type {

                    CMyDialog* m_p_native_target;

                public:

                    delegate_proxy_type(CMyDialog* pNativeTarget) :

                        m_p_native_target(pNativeTarget) {}

                    void OnWFBtnClick(Object^ sender, EventArgs^ e) {

                        this->m_p_native_target->OnWFBtnClick(sender, e);

                    }

                };

             

                void OnWFBtnClick(Object^ sender, EventArgs^ e) {

                    this->m_wfBtn->Text = "Thanks for clicking";

                }

             

                // other members

            };

             

            7 簡化CMyDialog

            class CMyDialog : public CDialog

            {

            public:

                CMyDialog(CWnd* pParent = NULL): CDialog(CMyDialog::IDD, pParent) {}

             

                enum { IDD = IDD_MYDIALOG };

             

            private:

                CWinFormsControl<Button> m_wfBtn;

             

            protected:

                virtual void DoDataExchange(CDataExchange* pDX) {

                    DDX_ManagedControl(pDX, IDC_WFBTN, this->m_wfBtn);

                }

             

            public:

                BEGIN_DELEGATE_MAP(CMyDialog)

                    EVENT_DELEGATE_ENTRY(OnWFBtnClick, Object^, EventArgs^)

                END_DELEGATE_MAP()

             

                void OnWFBtnClick(Object^ sender, EventArgs^ e) {

                    this->m_wfBtn->Text = "Thanks for clicking";

                }

             

            public:

                virtual BOOL OnInitDialog(){

                    CDialog::OnInitDialog();

             

                    this->m_wfBtn->Click += MAKE_DELEGATE(System::EventHandler,

                        OnWFBtnClick);

                    return TRUE;

                }

            };

             

            8 重載IView

            #using <mfcmifc80.dll>

            using Microsoft::VisualC::MFC::IView;

             

            public ref class MyWinFormsViewControl :

                public System::Windows::Forms::UserControl,

                public IView

            {

                ...

            protected: // IView implementation

                virtual void OnInitialUpdate() = IView::OnInitialUpdate {

                    // implementation

                }

             

                virtual void OnUpdate() = IView::OnUpdate {

                    // implementation

                }

             

                virtual void OnActivateView(bool activate) = IView::OnActivateView {

                    // implementation

                }

            };

             

            9 注冊命令處理程序

            public ref class MyWinFormsViewControl :

                public System::Windows::Forms::UserControl,

                public ICommandTarget

            {

            ...

            protected: // ICommandTarget implementation

                virtual void RegisterCmdHandlers(ICommandSource^ cmdSrc) =

                    ICommandTarget::Initialize

                {

                    cmdSrc->AddCommandHandler(ID_EDIT_PASTE,

                        gcnew CommandHandler(this, &WinFormsView::OnEditPaste));

                    cmdSrc->AddCommandUIHandler(ID_EDIT_PASTE,

                        gcnew CommandUIHandler(this,

                        &WinFormsView::OnUpdateEditPaste));

             

                    // register further command handlers ...

                }

             

                void OnEditPaste(unsigned int)

                {

                    // implement command handler

                }

             

                void OnUpdateEditPaste(unsigned int, ICommandUI^ cmdUI)

                {

                    cmdUI->Enabled = ...; // your logic here

                }

            };

             

            10 CreateWindowExHwndSourceParameters

            CreateWindowEx Arguments

            HwndSourceParameters Properties

            LPCTSTR lpClassName

            N/A

            N/A

            WindowClassStyle

            LPCTSTR lpWindowName

            WindowName

            DWORD dwStyle

            WindowStyle

            DWORD dwExStyle

            ExtendedWindowStyle

            int x

            PositionX

            int y

            PositionY

            int nWidth

            Width

            int nHeight

            Height

            HWND hWndParent

            ParentWindow

            HMENU hMenu

            N/A

            HINSTANCE hInstance

            N/A

             

            11 使用HwndSource

            BOOL CWPFDemoDialog::OnInitDialog()

            {

                __super::OnInitDialog();

               

                CRect rectClient;

                this->GetClientRect(&rectClient);

             

                System::Windows::Interop::HwndSourceParameters hwsPars;

                hwsPars.ParentWindow = System::IntPtr(this->m_hWnd);

                hwsPars.WindowStyle = WS_CHILD | WS_VISIBLE;

                hwsPars.PositionX = 0;

                hwsPars.PositionY = 0;

                hwsPars.Width = rectClient.Width();

                hwsPars.Height = rectClient.Height();

                System::Windows::Interop::HwndSource^ hws;

                hws = gcnew System::Windows::Interop::HwndSource(hwsPars);

             

                using System::Windows::Controls::MonthCalendar;

                MonthCalendar^ mc = gcnew MonthCalendar;   

                hws->RootVisual = mc;

             

                return TRUE;

            }

             

             

            詞匯表

            assignment

            賦值

            Common Language Infrastructure

            通用語言基礎構造

            command-routing infrastructure

            命令傳送基礎結構

            deregistration

            撤銷登記

            event handler delegates

            事件處理程序委托

            fields

            字段

            forward

            移交

            helper

            助手

            instantiates

            實例化

            interoperability

            互操作性

            in-place activated

            就地激活

            just-in-time

            實時

            map

            映射

            mix and match

            混合搭配

            native code

            本地代碼

            placeholder

            占位符

            template class

            模板類

            Windows Forms

            Windows 窗體

            posted on 2008-08-15 21:06 cpsprogramer 閱讀(2837) 評論(1)  編輯 收藏 引用 所屬分類: VC++

            FeedBack:
            # re: 通過C++ Interop把Windows窗體集成到MFC應用程序中  2008-08-17 17:44 dell筆記本
            C++ Interop我還是第一次接觸,的確很有價值的東西  回復  更多評論
              
            久久国产精品免费| 91久久成人免费| 亚洲国产日韩欧美综合久久| 国产福利电影一区二区三区,免费久久久久久久精 | 亚洲va久久久噜噜噜久久天堂| 狠狠色丁香婷婷久久综合| 久久久久免费精品国产| 国产精品九九九久久九九 | 久久AV无码精品人妻糸列| 色欲久久久天天天综合网精品| 久久综合久久综合久久综合| 久久无码国产| 99国产精品久久| 18禁黄久久久AAA片| 精品国产一区二区三区久久蜜臀| 久久久午夜精品福利内容| 久久国产精品77777| 国产一区二区久久久| 97精品国产97久久久久久免费| 国产成人无码精品久久久性色| 久久精品国产影库免费看| 久久久久青草线蕉综合超碰| 久久99精品久久久久久不卡 | 一本久久免费视频| 97久久精品人人做人人爽| 久久久无码人妻精品无码| 久久久久久久久66精品片| 国产激情久久久久影院| 成人妇女免费播放久久久| 亚洲乱码中文字幕久久孕妇黑人| 久久影视综合亚洲| 国产综合精品久久亚洲| 婷婷久久综合九色综合98| 午夜天堂av天堂久久久| 久久久无码精品亚洲日韩京东传媒 | 伊人久久大香线蕉无码麻豆| 99久久免费只有精品国产| 秋霞久久国产精品电影院| 91超碰碰碰碰久久久久久综合| 久久99久久99小草精品免视看| 久久国产高潮流白浆免费观看|