久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

通過C++ Interop把Windows窗體集成到MFC應(yīng)用程序中

 likeilike 2011-05-04

MSDN Mag 2006.05.

原文出處:Mix And Match: Integrate Windows Forms Into Your MFC Applications Through C++ Interop

翻譯:Steven Xiong

翻譯時間:2006516

http://www.cnblogs.com/bearblog/archive/2006/05/16/401809.html

 

混合匹配

通過C++ InteropWindows窗體集成到MFC應(yīng)用程序中

Marcus Heege

 

這篇文章討論:

  • C++ Interop如何工作
  • 在項目中何時使用C++ Interop
  • MFC應(yīng)用中使用Windows窗體控件
  • Windows窗體轉(zhuǎn)到WPF視圖

 

這篇文章使用了以下技術(shù):

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

 

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

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

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

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

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

 

 
1 MTS

 

C++ Interop是你的朋友

我的經(jīng)驗表明,C++ Interop是非??煽康?,盡管它有一些限制,但還是值得把它加入到你的開發(fā)工具箱中,。要理解這一特性是如何工作的,,你應(yīng)當(dāng)認(rèn)識到C++ Interop.NET Framework的一個設(shè)計特性。作為.NET Framework基礎(chǔ)規(guī)格的通用語言基礎(chǔ)架構(gòu)(CLI),,已經(jīng)支持了這一特性,。事實上,CLI的一些方面被定義,,僅僅是因為C++ Interop需要它們,。

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

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

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

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

 

何時使用C++ Interop

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

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

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

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

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

 

MFC應(yīng)用中的Windows窗體控件

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

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

public interface IWin32Window {

 property IntPtr Handle {

    IntPtr get ();

 }

};

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

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

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

 


4
 使用ActiveX控件

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

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

m_wfBtn.Text = "Click me!";

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

 

處理控件事件

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

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

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

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

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

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

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

class CMyDialog : public CDialog {

    ref class nested_managed_class {

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

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

        }

    };

    // 其他成員

};

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

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

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

運用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定義了包含有委托目標(biāo)的delegate_proxy_type。每一個EVENT_DELEGATE_ENTRY行在托管類中增加了一個目標(biāo)方法,。END_DELEGATE_MAP只是結(jié)束了托管類,。最后,MAKE_DELEGATE實例化一個指向delegate_proxy_type的目標(biāo)方法的委托,。實際上,,這些宏做的事情比我剛才討論的還要更多。它們甚至為以下場景做好了準(zhǔn)備,在托管類發(fā)生的事件要被發(fā)送給一個不再存在的本地對象,。

 

作為對話框的控件

另一個簡單但有效的助手是CWinFormsDialog模板,。你可以使用它以模態(tài)或非模態(tài)對話框的形式來展示一個Windows窗體控件。這個類相當(dāng)簡單,。它擴展CDialog來提供MFC對話框的標(biāo)準(zhǔn)行為,。

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

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

CWinFormsDialog<YourWinFormsDlgControl>().DoModal();

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

Windows窗體視圖

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

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

class CMyWinFormsBasedView : public CWinFormsView

{

    CMyWinFormsBasedView ();

    DECLARE_DYNCREATE(CMyWinFormsBasedView)

};

如果你的視圖類是由向?qū)傻?,你?yīng)當(dāng)確保不僅在你的視圖類定義的基類列表中,而且在它的實現(xiàn)中,,改換成CWinFormsView,。你可能要改變宏的參數(shù),如IMPLEMENT_DYNAMICBEGIN_MESSAGE_MAP宏。要實例化被宿主的Windows窗體控件,CWinFormsView(你的視圖基類)的構(gòu)造函數(shù)得到一個指向Windows窗體控件的System::Type對象的句柄,。視圖類的實現(xiàn)也非常簡單,,如下所示:

IMPLEMENT_DYNCREATE(CMyWinFormsBasedView, CWinFormsView)

 

CMyWinFormsBasedView:: CMyWinFormsBasedView ()

    : CWinFormsView(WinFormsViewControl::typeid) {}

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

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

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

interface class ICommandTarget

{

    void Initialize(ICommandSource^ commandSource);

};

當(dāng)實現(xiàn)ICommandTarget的視圖被創(chuàng)建時,,在那個視圖上,ICommandTarget::Initialize被調(diào)用,,一個新命令源對象的句柄被當(dāng)作參數(shù)傳遞,。這個參數(shù)的類型是ICommandSource^。參數(shù)所指的對象是一個許多處理程序的容器,。這些處理程序?qū)τ?/span>MFC開發(fā)人員來說,,聽起來應(yīng)當(dāng)很熟悉:它們是當(dāng)一個命令發(fā)出時被調(diào)用的命令處理程序;控制控件的UI是否使能,、選中,,或用單選按鈕裝飾,以及在命令UI中顯示什么樣的文字的命令UI處理程序,。

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

delegate void CommandHandler(unsigned int);

delegate void CommandUIHandler(unsigned int,

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

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

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

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

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

 

 

通向Avalon之橋

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

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

HwndSource構(gòu)造函數(shù)期望HwndSourceParameters的值類型作為參數(shù),。如10所示,,這一值類型包含了與調(diào)用Win32函數(shù)CreateWindowEx所傳遞參數(shù)相似的信息。11展示了在OnInitDialog實現(xiàn)中如何使用HwndSource,。

 

總結(jié)

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

還有一件事情,,是把這些特性無縫地集成到Visual Studio的向?qū)е?。在大多?shù)的場景中,因為很多實現(xiàn)將被遺留到被宿主的Windows窗體控件中,,所以這并不是一個大的問題,,而Windows窗體控件在Visual Studio中得到了很好的支持。當(dāng)Windows Presentation Foundation發(fā)布時,,為了在MFC應(yīng)用中集成Visuals,,提供對等支持的可能性是很大的。即使沒有這種支持,,在MFC應(yīng)用中宿主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..


From the May 2006 issue of MSDN Magazine.

 

2 創(chuàng)建一個被宿主控件

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 宿主一個有對話框數(shù)據(jù)交換(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

通用語言基礎(chǔ)構(gòu)造

command-routing infrastructure

命令傳送基礎(chǔ)結(jié)構(gòu)

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 窗體

 

Revision

V1.1Windows Forms的翻譯由“Windows表單”修改為“Windows 窗體”(517日)

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多