270 likes | 611 Views
DEV331 Visual C++: Using The .NET Framework In Win32/MFC Applications. Kate Gregory Gregory Consulting Limited. Timeline. First release: Visual C++ .NET 2002 New reserved keywords: __gc etc Interop Limited designer support Current release: Visual C++ .NET 2003 Still great interop
E N D
DEV331 Visual C++: Using The .NET Framework In Win32/MFC Applications Kate Gregory Gregory Consulting Limited
Timeline • First release: Visual C++ .NET 2002 • New reserved keywords: __gc etc • Interop • Limited designer support • Current release: Visual C++ .NET 2003 • Still great interop • WinForms designer • Amazing conformance to standard C++ • Goodies for unmanaged C++ devs • Next release: Visual C++ 2005 • codename Whidbey • Language changes • More to follow • Longhorn, Avalon, WinFX, Indigo...
The problem • Existing code is too valuable to throw away • No-one wants to be left behind as functionality advances • So many things are different between MFC and WinForms • Popular data types • Event handling • Lifetime management • Global and static scope
Why Stay In C++? • I like it • Templates • Destructors • Syntax • I want the highest-performing interop • I want to combine managed and unmanaged code • I’m a control freak • Switching languages is confusing
Options • Call your old library from a new WinForm app • Usually requires refactoring • Call new .NET code from your MFC business layer • From unmanaged: interop • Or compile parts as managed • Add a WinForm to your MFC UI • Host the CLR • All about placing the boundary
Refactoring • Easiest MFC apps to move to the new world have separate presentation and logic • Business layer, data layer • Pass business objects (Employee) between layers rather than CRecordset or other library-specific types • Converting your application to a more modular one is often the first step in porting
Refactoring Old monolithic app New Data Layer New Business Layer New MFC UI New Web Services New WinForm UI . . .
Calling The Business Layer • The business layer is an ordinary “classic” C++ class library • Unmanaged • Preferably not using MFC • Call it: #include the header file and linking to the .lib • Just the same from managed C++ or unmanaged C++ • Much easier from C++ than other managed languages
Calling .NET Code From MFC Code • If your MFC code is compiled with /CLR, it can access any .NET objects trivially • This is the big C++ advantage
Calling .NET Code From MFC Code • Create COM-Callable Wrapper around the .NET Objects • Strong name • Regasm • Gacutil • tlbexp • Unmanaged code calls them as though they were COM Components • #import the tlb
Options • Call your old library from a new WinForm app • Usually requires refactoring • Call new .NET code from your MFC business layer • From unmanaged: interop • Or compile parts as managed • Add a WinForm to your MFC UI • Host the CLR • All about placing the boundary
WinForm In An MFC View • MFC App is compiled with /clr • Not the only choice, but a simple option • WinForm is accessed as a managed object but also wrapped in a COleControlSite • MFC View creates instance of WinForm, gets an IUnknown from it, and gets it onto the view • Use gcroot<>, CCOMPtr<>, and other managed-unmanaged helpers • Calling methods of the managed object is easy
TestMFCFormView.h • The managed object: gcroot<Controls::ControlsControl*> pWrappedControl; • Helper class from ManagedControlHelpers CWinFormsControlWnd m_usercontrol; • Ordinary click handler: afx_msg void OnBnClickedButton1();
OnInitialUpdate CFormView::OnInitialUpdate(); ResizeParentToFit(); Controls::ControlsControl* pControl = new Controls::ControlsControl(); pWrappedControl = pControl; CComPtr<IUnknown> spunkControl; spunkControl.Attach((IUnknown*)System::Runtime:: InteropServices::Marshal::GetIUnknownForObject( pControl).ToPointer()); CWnd* pwnd = this->GetDlgItem(IDC_PLACEHOLDER); CRect rectPlaceHolder; pwnd->GetWindowRect(&rectPlaceHolder); this->ScreenToClient(rectPlaceHolder); pwnd->ShowWindow(SW_HIDE); m_usercontrol.Create(spunkControl, WS_VISIBLE | WS_TABSTOP, rectPlaceHolder, this, 0);
Click HandlerMFC calls WinForm • Very simple, use the original managed object that was wrapped: void CTestMFCFormView::OnBnClickedButton1() { UpdateData(true); pWrappedControl->LabelText = SendText; }
Click HandlerWinForm calls MFC • This is significantly harder • Define a managed interface for WinForm to call • Define an unmanaged interface with the same methods • Have the MFC View implement the unmanaged interface • Write a managed bridge class
Managed Interface public __gc __interface IViewLabel { __property String* get_Text(); __property void set_Text(String*); };
Equivalent Unmanaged Interface class IUnmanViewLabel { public: virtual char* get_Text()=0; virtual void set_Text(char* t)=0; };
Bridge 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 Class String* ViewLabelImpl::get_Text() { return new String(view->get_Text()); } void ViewLabelImpl::set_Text(String* t) { //incredibly ugly marshaling code //producing s, a char* view->set_Text(s); }
Options • Call your old library from a new WinForm app • Usually requires refactoring • Call new .NET code from your MFC business layer • From unmanaged: interop • Or compile parts as managed • Add a WinForm to your MFC UI • Host the CLR • All about placing the boundary
Hosting The CLR • This is usually a last resort • Unless your app is IIS, Office, SQL Server • Your unmanaged code thinks it is calling COM APIs • The CLR is loaded and managed code runs • Take complete control of your app: when the load cost happens, how the AppDomains are managed, and so on • Not for the faint of heart
Boundary Placement • Transition cost for switching from managed to unmanaged • Managed wrapper around unmanaged code will cross boundary many times • For chatty calls consider adding an unmanaged wrapper with a chunky interface • All the chat happens entirely in unmanaged world • Similar logic when unmanaged code is calling BCL or new managed code
What's Next? • Whidbey • Longhorn • Be ready
Please fill out a session evaluation on CommNet Q1: Overall satisfaction with the session Q2: Usefulness of the information Q3: Presenter’s knowledge of the subject Q4: Presenter’s presentation skills Q5: Effectiveness of the presentation