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

Preview:

Citation preview

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

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

Agenda

Setting the stageCOM InteropPInvokeIt Just WorksWhat should you do?

The Legacy

class ArithmeticClass{public:

double Add( double num1, double num2);

};

Unmanaged application

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

return 0;}

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?

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

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

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

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;

}

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

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;

}

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

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

Finding the DLLAdd the import library to the dependencies

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

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!

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!

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!

XCopy PortingBuilds to IL

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

May gain performance

Give up being managed

A Mixed ExeUse the property pages for the file

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

Agenda

Setting the stageCOM InteropPInvokeIt Just WorksWhat should you do?

What Should You Do?

PerformanceMaintenance Convenience and Development TimeSecurity and Permissions

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

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

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

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?

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

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

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

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

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

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;

Resources and Links

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

MSDNmsdn.microsoft.com/visualc/

GotDotNetwww.gotdotnet.com/team/cplusplus/

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

evaluationsevaluations

© 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.

Recommended