40
DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Embed Size (px)

Citation preview

Page 1: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

DEV 420 Head-Spinning C++ Managed-Native Interoperability

Kate Gregory

Gregory Consulting

Page 2: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Too Much Choice?

Millions of lines of C++ code already existBusiness logic

Proprietary algorithms

Class libraries from long-dead vendors

This code is not going anywhereIt’s tested

It works

It’s paid for

Page 3: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Session Prerequisites

Familiarity with the .NET Framework and the CLR

Experience developing in Managed C++

Experience developing in unmanaged C++MFC

ATL

Another compiler or class library

Familiarity with COM concepts

Page 4: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Agenda

Setting the stageCOM InteropPInvokeIt Just WorksWhat should you do?

Page 5: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

The Legacy

class ArithmeticClass{public:

double Add( double num1, double num2);

};

Page 6: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Unmanaged application

int _tmain(void){ArithmeticClass arith;cout << "1 + 2 is " << arith.Add(1,2) << endl;

return 0;}

Page 7: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Making the Legacy Available

You’re writing a new Managed C++ application

Or a VB.NET or C# application and you don’t mind it having some Managed C++ portions

You want to use your legacy library

You know there are tradeoffsYour effort

Performance

What else?

Page 8: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

COM Interop

Managed code can use a COM component as simply as a .NET object

Runtime Callable Wrapper (RCW) looks like a .NET object on the outside, but inside it uses a COM component

Holds GUIDs, progids etc

Translates casts into QueryInterface, new into CoCreateInstance, etc

Handles reference counting

Can be generated automatically since a type library can map to an assembly’s metadata

Page 9: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

How do you make an RCW?

From Managed C++ project, add a reference

Use the COM tab

Produces a passable RCW automaticallyMarshals between COM and .NET types

Handles QI and Reference Counting

Turns HRESULTs into exceptions

It is possible to write your own “Interop Assembly” if you really need to

Page 10: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Wrap the Legacy in COM

ATL ProjectAdd Simple ATL Object

Retype method definitions into wizardPaste method bodies into project

Could create a wrapper that called into a LIB or DLL

Page 11: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Using the COM Object#import "..\ComArithmetic\Debug\ComArithmetic.dll"

no_namespace

int _tmain(int argc, _TCHAR* argv[]){

::CoInitialize(NULL);//braces for scope only{IArithmeticClassPtr arith("ComArithmetic.ArithmeticClass");double answer = arith->Add(1,3);cout << "1 + 3 is " << answer << endl;cin.get();}::CoUninitialize();return 0;

}

Page 12: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Using COM from .NET

int _tmain(void){

ComArithmetic::CArithmeticClassClass*arith = new

ComArithmetic::CArithmeticClassClass(); double answer = arith->Add(2,3); Console::Write("2 + 3 is "); Console::WriteLine(__box(answer));

return 0;}

Page 13: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Wrap the Legacy as a DLL

Win32 project, application type is DLLPull member functions out of the class

Add declspec to each

extern "C" __declspec(dllexport) double Add(double num1, double num2)

{return num1+ num2;

}

Page 14: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Using the DLL from .NET

using namespace System::Runtime::InteropServices;

[DllImport("debug/dllarithmeticglobal.dll")] extern "C" double Add(double num1, double

num2);int _tmain(void){ double answer = Add(4,3); Console::Write("4 + 3 is "); Console::WriteLine(__box(answer)); return 0;}

Page 15: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

C++ Is Special

If the Pinvoke defaults are fine with you, leave it out:

extern "C" double Add(double num1, double num2);

int _tmain(void){ double answer = Add(4,3); Console::Write("4 + 3 is "); Console::WriteLine(__box(answer));return 0;}

Page 16: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Finding the DLLAdd the import library to the dependencies

Page 17: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Finding the DLLMake sure the import library is on the linker dependency pathMake sure the DLL is on the executable search path

Page 18: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

C++ Is Special

What is happening in this example?No Pinvoke

Linking to a .lib that has unmanaged code

Nothing special about the function declaration

You can even use the .h file from the DLL project with __declspec(dllexport) in it, and the compiler just ignores the declspec

It Just Works!

Page 19: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

It Just Works

If you have unmanaged code you want to compile as managed, just compile it

It will compileIt will run

Even if it calls out to unmanaged codeStatically linkedDynamically linkedMFCATLWhatever!

Page 20: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

XCopy Porting

Create a new managed applicationCopy the .cpp files and .h files into the project folder

These create non-gc classesProbably call out to other libraries

Use Add, Add Existing ItemNow the code is in the project

Build it!

Page 21: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

XCopy PortingBuilds to IL

Page 22: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

A Mixed ExeFile-by-file, you can request native code instead of IL

May gain performance

Give up being managed

Page 23: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

A Mixed ExeUse the property pages for the file

Page 24: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

A Mixed Exe

You can also control managed or unmanaged compilation within a file:Before a function:

#pragma unmanagedint foo();

Use with caution, it can confuse maintainers

Page 25: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Agenda

Setting the stageCOM InteropPInvokeIt Just WorksWhat should you do?

Page 26: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

What Should You Do?

PerformanceMaintenance Convenience and Development TimeSecurity and Permissions

Page 27: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Performance

Usually unmanaged code called from unmanaged code is the fastest solution

Sometimes the xcopy port can surprise you

XCopy port may get faster if you make individual files compile to native code

DLL (with or without PInvoke) is slower than these two, but faster than COM

It’s a trace faster without PInvoke

COM Interop has the most overhead

Page 28: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Maintenance

What other applications are using this code now?

How do they call it?

Crazy to maintain a COM component and a class library as separate copies

Even if the class library does execute a bit faster under .NET

Maybe some refactoring is the way to go in that case

Pull functionality into a class libraryCOM component and .NET component both use the class library

Page 29: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Developer Convenience

This is all pretty easy, really

Still, why run around refactoring or wrapping if you don’t need to?

Hard to argue with It Just Works

Avoid maintaining two sets of code, but don’t create wrappers for their own sake

Page 30: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Security

Code Access SecurityGranular Permissions

Access file systemMake SQL connectionCall unmanaged code

Surely each of the ways of reusing legacy C++ code has different security implications?

Page 31: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Skip Verification

By default, all C++ projects demand SkipVerification permission

The IL doesn’t have to pass the Verifier checks

All means allCOM Interop

Pinvoke

XCopy port, 100 % IL

Mixed EXE

No security implications of the reuse choice

Page 32: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Verifiable Code

Starting in Visual Studio .NET 2003, C++ projects can turn off the SkipVerification request, but they must be verifiable

Hardly any C++ code will meet the requirements for verifiable code

No pointer arithmetic

No linking to unmanaged code (IJW), or #pragma unmanaged – no CRT

PInvoke OK

Optimizer off

Page 33: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Bottom Line

If the code you want to reuse is not being used in any other application

XCopy Port

If the code is a COM Component nowCOM Interop

If you notice a performance issue, refactor to a library and a COM component, and use the library from .NET

If the code is a DLL nowUse PInvoke if you need to control marshaling

Otherwise IJW

Page 34: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

What About VB and C#?

They can only get to your old code through COM Interop or PInvokeBut you can write a little wrapper class

Managed (__gc) class in Managed C++Wraps each method of the old class and calls it using IJW VB and C# can use language interop on the CLR to call these methodsC++ provides the bridge to the old world

Maximizes performance

Page 35: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Wrapper class

public __gc class ArithmeticWrapper{private: ArithmeticClass* ac;public: ArithmeticWrapper() {ac = new ArithmeticClass();} double Add(double num1, double num2) {return ac->Add(num1,num2);} ~ArithmeticWrapper() {delete ac;}};

Page 36: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Why not make ArithmeticClass __gc?

Can't allocate on stackOld code will break

Can you delete a pointer to a garbage-collected class?

Yes:ArithmeticWrapper* wrapper = new

ArithmeticWrapper();answer = wrapper->Add(5,6);delete wrapper;

Page 37: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Resources and Links

My Code Guru Column www.codeguru.com/columns/Kate/

MSDNmsdn.microsoft.com/visualc/

GotDotNetwww.gotdotnet.com/team/cplusplus/

Page 38: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

Community Resources

Community Resourceshttp://www.microsoft.com/communities/default.mspx

Most Valuable Professional (MVP)http://www.mvp.support.microsoft.com/

NewsgroupsConverse online with Microsoft Newsgroups, including Worldwidehttp://www.microsoft.com/communities/newsgroups/default.mspx

User GroupsMeet and learn with your peershttp://www.microsoft.com/communities/usergroups/default.mspx

Page 39: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

evaluationsevaluations

Page 40: DEV 420 Head-Spinning C++ Managed-Native Interoperability Kate Gregory Gregory Consulting

© 2002 Microsoft Corporation. All rights reserved.© 2002 Microsoft Corporation. All rights reserved.This presentation is for informational purposes only. Microsoft makes no warranties, express or implied, in this summary.This presentation is for informational purposes only. Microsoft makes no warranties, express or implied, in this summary.