View
248
Download
2
Category
Tags:
Preview:
Citation preview
DEV331 Visual C++: Using The .NET Framework In Win32/MFC Applications
DEV331 Visual C++: Using The .NET Framework In Win32/MFC Applications
Kate GregoryKate GregoryGregory Consulting LimitedGregory Consulting Limited
TimelineTimeline
First release: Visual C++ .NET 2002First release: Visual C++ .NET 2002New reserved keywords: __gc etcNew reserved keywords: __gc etc
InteropInterop
Limited designer supportLimited designer support
Current release: Visual C++ .NET 2003Current release: Visual C++ .NET 2003Still great interopStill great interop
WinForms designerWinForms designer
Amazing conformance to standard C++Amazing conformance to standard C++
Goodies for unmanaged C++ devsGoodies for unmanaged C++ devs
Next release: Visual C++ 2005Next release: Visual C++ 2005codename Whidbeycodename Whidbey
Language changesLanguage changes
More to followMore to followLonghorn, Avalon, WinFX, Indigo...Longhorn, Avalon, WinFX, Indigo...
The problemThe problem
Existing code is too valuable to Existing code is too valuable to throw awaythrow away
No-one wants to be left behind as No-one wants to be left behind as functionality advancesfunctionality advances
So many things are different between So many things are different between MFC and WinFormsMFC and WinForms
Popular data typesPopular data types
Event handlingEvent handling
Lifetime managementLifetime management
Global and static scopeGlobal and static scope
Why Stay In C++?Why Stay In C++?
I like itI like itTemplatesTemplates
DestructorsDestructors
Syntax Syntax
I want the highest-performing interopI want the highest-performing interop
I want to combine managed and I want to combine managed and unmanaged code unmanaged code
I’m a control freakI’m a control freak
Switching languages is confusingSwitching languages is confusing
OptionsOptions
Call your old library from a new Call your old library from a new WinForm appWinForm app
Usually requires refactoringUsually requires refactoring
Call new .NET code from your MFC Call new .NET code from your MFC business layerbusiness layer
From unmanaged: interopFrom unmanaged: interop
Or compile parts as managedOr compile parts as managed
Add a WinForm to your MFC UIAdd a WinForm to your MFC UI
Host the CLRHost the CLR
All about placing the boundaryAll about placing the boundary
RefactoringRefactoring
Easiest MFC apps to move to the new Easiest MFC apps to move to the new world have separate presentation world have separate presentation and logicand logic
Business layer, data layerBusiness layer, data layer
Pass business objects (Employee) Pass business objects (Employee) between layers rather than CRecordset or between layers rather than CRecordset or other library-specific typesother library-specific types
Converting your application to a Converting your application to a more modular one is often the first more modular one is often the first step in portingstep in porting
RefactoringRefactoring
New New MFC UIMFC UI
New New Business LayerBusiness Layer
New New Data Data LayerLayer
Old monolithic app
New New WinForm UIWinForm UI
New New Web Web
ServicesServices. . . . . .
Calling The Business LayerCalling The Business Layer
The business layer is an ordinary The business layer is an ordinary “classic” C++ class library“classic” C++ class library
UnmanagedUnmanaged
Preferably not using MFCPreferably not using MFC
Call it: #include the header file and Call it: #include the header file and linking to the .liblinking to the .lib
Just the same from managed C++ or Just the same from managed C++ or unmanaged C++unmanaged C++
Much easier from C++ than other Much easier from C++ than other managed languagesmanaged languages
Calling .NET Code From MFC CodeCalling .NET Code From MFC Code
If your MFC code is compiled with If your MFC code is compiled with /CLR, it can access any .NET objects /CLR, it can access any .NET objects triviallytrivially
This is the big C++ advantageThis is the big C++ advantage
Calling .NET Code From MFC CodeCalling .NET Code From MFC Code
Create COM-Callable Wrapper around Create COM-Callable Wrapper around the .NET Objectsthe .NET Objects
Strong nameStrong name
RegasmRegasm
GacutilGacutil
tlbexptlbexp
Unmanaged code calls them as though Unmanaged code calls them as though they were COM Componentsthey were COM Components
#import the tlb#import the tlb
OptionsOptions
Call your old library from a new Call your old library from a new WinForm appWinForm app
Usually requires refactoringUsually requires refactoring
Call new .NET code from your MFC Call new .NET code from your MFC business layerbusiness layer
From unmanaged: interopFrom unmanaged: interop
Or compile parts as managedOr compile parts as managed
Add a WinForm to your MFC UIAdd a WinForm to your MFC UI
Host the CLRHost the CLR
All about placing the boundaryAll about placing the boundary
WinForm In An MFC ViewWinForm In An MFC View
MFC App is compiled with /clr MFC App is compiled with /clr Not the only choice, but a simple optionNot the only choice, but a simple option
WinForm is accessed as a managed object WinForm is accessed as a managed object but also wrapped in a COleControlSitebut also wrapped in a COleControlSite
MFC View creates instance of WinForm, MFC View creates instance of WinForm, gets an IUnknown from it, and gets it onto gets an IUnknown from it, and gets it onto the viewthe view
Use gcroot<>, CCOMPtr<>, and other Use gcroot<>, CCOMPtr<>, and other managed-unmanaged helpersmanaged-unmanaged helpers
Calling methods of the managed object Calling methods of the managed object is easyis easy
TestMFCFormView.h TestMFCFormView.h
The managed object: The managed object: gcroot<Controls::ControlsControl*> gcroot<Controls::ControlsControl*>
pWrappedControl;pWrappedControl;
Helper class from ManagedControlHelpersHelper class from ManagedControlHelpersCWinFormsControlWnd m_usercontrol;CWinFormsControlWnd m_usercontrol;
Ordinary click handler: Ordinary click handler: afx_msg void OnBnClickedButton1();afx_msg void OnBnClickedButton1();
OnInitialUpdateOnInitialUpdateCFormView::OnInitialUpdate();CFormView::OnInitialUpdate();ResizeParentToFit();ResizeParentToFit();
Controls::ControlsControl* pControl = Controls::ControlsControl* pControl = new Controls::ControlsControl();new Controls::ControlsControl();
pWrappedControl = pControl;pWrappedControl = pControl;
CComPtr<IUnknown> spunkControl;CComPtr<IUnknown> spunkControl;spunkControl.Attach((IUnknown*)System::Runtime::spunkControl.Attach((IUnknown*)System::Runtime::
InteropServices::Marshal::GetIUnknownForObject(InteropServices::Marshal::GetIUnknownForObject(pControl).ToPointer());pControl).ToPointer());
CWnd* pwnd = this->GetDlgItem(IDC_PLACEHOLDER);CWnd* pwnd = this->GetDlgItem(IDC_PLACEHOLDER);CRect rectPlaceHolder;CRect rectPlaceHolder;pwnd->GetWindowRect(&rectPlaceHolder);pwnd->GetWindowRect(&rectPlaceHolder);this->ScreenToClient(rectPlaceHolder);this->ScreenToClient(rectPlaceHolder);pwnd->ShowWindow(SW_HIDE);pwnd->ShowWindow(SW_HIDE);
m_usercontrol.Create(spunkControl, WS_VISIBLE | WS_TABSTOP, m_usercontrol.Create(spunkControl, WS_VISIBLE | WS_TABSTOP, rectPlaceHolder, this, 0);rectPlaceHolder, this, 0);
Click HandlerMFC calls WinFormClick HandlerMFC calls WinForm
Very simple, use the original managed Very simple, use the original managed object that was wrapped:object that was wrapped:
void CTestMFCFormView::OnBnClickedButton1()
{
UpdateData(true);
pWrappedControl->LabelText = SendText;
}
Click HandlerWinForm calls MFCClick HandlerWinForm calls MFC
This is significantly harderThis is significantly harder
Define a managed interface for Define a managed interface for WinForm to callWinForm to call
Define an unmanaged interface with Define an unmanaged interface with the same methodsthe same methods
Have the MFC View implement the Have the MFC View implement the unmanaged interfaceunmanaged interface
Write a managed bridge classWrite a managed bridge class
Managed InterfaceManaged Interface
public __gc __interface IViewLabelpublic __gc __interface IViewLabel
{{
__property String* get_Text();__property String* get_Text();
__property void set_Text(String*);__property void set_Text(String*);
};};
Equivalent Unmanaged InterfaceEquivalent Unmanaged Interfaceclass IUnmanViewLabelclass IUnmanViewLabel
{{
public:public:
virtual char* get_Text()=0;virtual char* get_Text()=0;
virtual void set_Text(char* t)=0;virtual void set_Text(char* t)=0;
};};
Bridge ClassBridge Class
public __gc class ViewLabelImpl: public IViewLabel
{public: ViewLabelImpl(IUnmanViewLabel* v); ~ViewLabelImpl(void); __property String* get_Text(); __property void set_Text(String*); private: IUnmanViewLabel* view;};
Bridge ClassBridge Class
String* ViewLabelImpl::get_Text()String* ViewLabelImpl::get_Text()
{{
return new String(view->get_Text());return new String(view->get_Text());
}}
void ViewLabelImpl::set_Text(String* t)void ViewLabelImpl::set_Text(String* t)
{{
//incredibly ugly marshaling code//incredibly ugly marshaling code
//producing s, a char*//producing s, a char*
view->set_Text(s);view->set_Text(s);
}}
OptionsOptions
Call your old library from a new Call your old library from a new WinForm appWinForm app
Usually requires refactoringUsually requires refactoring
Call new .NET code from your MFC Call new .NET code from your MFC business layerbusiness layer
From unmanaged: interopFrom unmanaged: interop
Or compile parts as managedOr compile parts as managed
Add a WinForm to your MFC UIAdd a WinForm to your MFC UI
Host the CLRHost the CLR
All about placing the boundaryAll about placing the boundary
Hosting The CLRHosting The CLR
This is usually a last resortThis is usually a last resortUnless your app is IIS, Office, SQL ServerUnless your app is IIS, Office, SQL Server
Your unmanaged code thinks it is Your unmanaged code thinks it is calling COM APIscalling COM APIs
The CLR is loaded and managed The CLR is loaded and managed code runscode runs
Take complete control of your app: Take complete control of your app: when the load cost happens, how the when the load cost happens, how the AppDomains are managed, and so onAppDomains are managed, and so on
Not for the faint of heartNot for the faint of heart
Boundary PlacementBoundary Placement
Transition cost for switching from Transition cost for switching from managed to unmanagedmanaged to unmanaged
Managed wrapper around unmanaged Managed wrapper around unmanaged code will cross boundary many timescode will cross boundary many times
For chatty calls consider adding an For chatty calls consider adding an unmanaged wrapper with a chunky unmanaged wrapper with a chunky interfaceinterface
All the chat happens entirely in All the chat happens entirely in unmanaged worldunmanaged world
Similar logic when unmanaged code is Similar logic when unmanaged code is calling BCL or new managed codecalling BCL or new managed code
Q1:Q1: Overall satisfaction with the sessionOverall satisfaction with the session
Q2:Q2: Usefulness of the informationUsefulness of the information
Q3:Q3: Presenter’s knowledge of the subjectPresenter’s knowledge of the subject
Q4:Q4: Presenter’s presentation skillsPresenter’s presentation skills
Q5:Q5: Effectiveness of the presentationEffectiveness of the presentation
Please fill out a session evaluation on CommNetPlease fill out a session evaluation on CommNet
Recommended