27
DEV331 Visual C++: Using The .NET Framework In Win32/MFC Applications Kate Gregory Kate Gregory Gregory Consulting Limited Gregory Consulting Limited

DEV331 Visual C++: Using The.NET Framework In Win32/MFC Applications Kate Gregory Gregory Consulting Limited

Embed Size (px)

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

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);

}}

Working TogetherWorking Together

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

What's Next?What's Next?

WhidbeyWhidbey

LonghornLonghorn

Be readyBe ready

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