50
COM Interop & P/Invoke .NET and the Old World

COM Interop & P/Invoke - Operating Systems and Middleware Group at

  • Upload
    others

  • View
    5

  • Download
    0

Embed Size (px)

Citation preview

Page 1: COM Interop & P/Invoke - Operating Systems and Middleware Group at

COM Interop & P/Invoke

.NET and the Old World

Page 2: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Objectives

Introduction to interoperation between.NET and COMCOM and .NET.NET and platform services

Page 3: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Contents

Section 1: Overview

Section 2: Calling COM Services from .NET

Section 3: Calling .NET Services from COM

Section 4: Calling Platform Services from .NET

Page 4: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Existing Stuff Must Coexist

Transition to .NET will be a lasting process

Portions of systems will remain as they are now...and even maintained in their current form

Interoperability increases the momentum of .NET

Goal is to achieve total transparency

Mere presence of .NET must not interfere with COM

Performance should not be hit

Page 5: COM Interop & P/Invoke - Operating Systems and Middleware Group at

What is different in the two Worlds?

Managed Code vs. Unmanaged CodeLifetime managementMetadata

Common Type System

Inheritance concept

Threading model

Error handling mechanisms

Registration

Page 6: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Calling COM Services from .NET

Metadata for COM class must be availableCan be generated from Type LibraryCan declare Custom Wrapper

Use COM class like .NET class

Early and late bound activation

COM component must be registered locally

Page 7: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Early Bound Activation

Instantiate like creating a .NET object

Metadata must be available at compile timeMust be referenced in development environment

At runtime, Metadata and COM library must be available

COMLib.COMClass aCOMObject;

aCOMObject = new COMLib.COMClass;

Page 8: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Runtime Callable WrappersPreserving object identity

Maintaining object lifetime

Proxying interfaces

Marshalling method calls

Consuming selected interfaces

.NET Object

COM Object RCW

IUnknownIDispatch

IIfcIIfc

Page 9: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Consuming Selected Interfaces

ISupportErrorInfo

Additional information with exceptions

IProvideClassInfo

Typed wrapper

ITypeInfo

TlbImp converts references to System.Type

Page 10: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Identity and Lifetime Control

COM lifetime control is wrapped by RCW

COM object released when RCW garbage collected

Non-deterministic finalization issue

COMLib.COMClass aCOMObject;

aCOMObject = new COMLib.COMClass();

aCOMObject.SomeFunc();

Marshal.ReleaseComObject(aCOMObject);

Page 11: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Converting Type Library to MetadataUse SDK tool TlbImp

Or just add reference to server in Visual Studio

Type library can be imported from executable

Reference resulting metadata file in project

Custom IDL attributes are preservedIDL:

[custom(„FE42746F-...-AC...84178”, “Value”)]

.NET:

[IdlAttribute(„FE42746F-...-AC...84178”, “Value”)]

Page 12: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Conversions by TlbImp 1/2

Library level Library to namespace

Module is converted to classConstants within module to constants within that classModule functions to static members of the class

library COMLib { interface Widget {}; coclass Slingshot {};

}

namespace COMLib { interface Widget {}; class Slingshot {};

}

custom(0F21F359-AB84-41e8-9A78-36D110E6D2F9, „MyNamespace.Class")

Page 13: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Conversions by TlbImp 2/2

InterfacesBase interfaces IUnknown and IDispatch are stripped

Type definitions are not importedImported as the underlying types

PropertiesGenerates corresponding get and set

Events

namespace COMLib { interface Widget {}; class Slingshot {};

}

Page 14: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Marshalling Isomorphic Types

Integer, Float Values

Non-isomorphic TypesBooleans, Chars, Strings, Arrays, Objects

Copying vs. PinningIsomorphic Types are pinnedNon-Isomorphic Types are copiedWatch out with Unicode Strings!

Passing by value actually passes a reference!

Passing by reference creates new String

Page 15: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Marshalling a UnionUse attributed struct in .NET

StructLayout attribute forSequential layout – is a regular structureDefault Union layoutExplicit layout

[StructLayout(Layout.Explicit)] public class SYSTEM_INFO { [FieldOffset(0)] ulong OemId; [FieldOffset(4)] ulong PageSize; [FieldOffset(16)] ulong ActiveProcessorMask;[FieldOffset(20)] ulong NumberOfProcessors;[FieldOffset(24)] ulong ProcessorType;

}

Page 16: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Inheritance COM uses containment/aggregation

.NET adds implementation inheritance

Mixed-mode objectsManaged objects can derive from COM objects

Must have metadata available

Must be instantiatable

Must be aggregatable

Interfaces can be inheritedIUnknown, IDispatch derivation is removed

Page 17: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Calling an COM Servernamespace CallingCOMServer

{

using System;

using COMServerLib;

public class DotNET_COMClient

{...

public static int Main(string[] args)

{

MyCOMServer myS = new MyCOMServer();

return (myS.Add (17,4));

}

}

};

Page 18: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Late Bound Activation

Accomplished by Reflection APINo difference whether COM or .NET object

Type can be obtained from ProgID or ClsID

InvokeMember to access methods and properties

Metadata is not needed, but usefulCOM object is wrapped by __ComObject

Page 19: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Late Bound Call to COM Servernamespace LateBoundClient

{

using System.Reflection;...Type typ;Object obj;Object[] prms = new Object[2];int r;

typ = Type.GetTypeFromProgID(„MyLib.MyServer");obj = Activator.CreateInstance(typ);prms[0] = 10; prms[1] = 150;

r = (int)typ.InvokeMember(„aMethod", BindingFlags.InvokeMethod, null, obj, prms);

...

}

Page 20: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Calling an Automation Servernamespace AutomationClient{

using EmotionalTulip; using System.Reflection;...TulipApplication tulipApp = new TulipApplication();

Type t = tulipApp.GetType();Object[] prms = new Object[1];prms[0] = true;

t.InvokeMember("Visible", BindingFlags.SetProperty,null, tulipApp, prms);

t.InvokeMember("Exit", BindingFlags.InvokeMethod, null, tulipApp, null);

...}

Page 21: COM Interop & P/Invoke - Operating Systems and Middleware Group at

ThreadingMost COM objects are single threaded

.NET thread must initialize COM apartmentDeferred initialization Initialized either as MTA or STA

Runtime provides transparent use of COM threadsAccess apartment threaded objects through proxyCan avoid proxy by setting apartment state of thread

Page 22: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Let the runtime initialize the default MTA

Setting ApartmentState explicitly eliminates proxyDo before the object is created!

Using ApartmentState

using System.Threading;using APTOBJLib;

AptSimple obj = new AptSimple ();

obj.Counter = 1;

using System.Threading; using APTOBJLib;

Thread.CurrentThread.ApartmentState = ApartmentState.STA;

AptSimple obj = new AptSimple();

obj.Counter = 1;

Page 23: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Results and ExceptionsCOM reports errors via result code

.NET methods throws exceptionsRuntime manages transition

HRESULT specifies exception class

Extended information via IErrorInfoCOM object should implement interfaceErrorCode, HelpLink, MessageSource, StackTrace, TargetSite

PreserveSigAttribute in custom wrapperSuppresses translation to exception

Page 24: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Design for InteroperabilityProvide and register Type Libraries

Use Automation Compliant Data Types

Use Chunky CallsMarshalling may be costly

Explicitly Free External Resources

Avoid Using Members of System.ObjectObject, Equals, Finalize, GetHashCode, GetTypeMemberwiseClone and ToString

Page 25: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Restrictions and Limitations

void* parameters need marshalling

Success HRESULTS cannot be distinguishedFailure HRESULT do raise exceptionsSuccess code don‘t

Typedef do not get through

Variable length arrays cannot be imported

is imported asHRESULT DoSomething(int cb, [in] byte buf[]);

public void DoSomething(int cb, ref Byte buf);

Page 26: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Calling .NET Services from COM

Use .NET class like COM classType and methods must be public

Early and late bound activation

Convert Metadata to Type Library

Wrapper of .NET component must be registeredCan use RegAsm tool

Page 27: COM Interop & P/Invoke - Operating Systems and Middleware Group at

COM Callable Wrappers Responsibilities of the COM Callable Wrapper

Preserving Object Identity Maintaining object lifetime Proxying custom interfaces Marshalling method calls Synthezising selected interfaces

COM Object CCW

.NET Object

IUnknownIDispatch

IIfc

IIfc

Page 28: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Identity and Lifetime Control Single CCW for .NET class insures identity

No matter how many COM classes call to itNo matter how object is created

Each interface of the CCW is referenced countedNo reference counting on the managed object

Managed objects lives at least while the CCW livesBut finalization is undeterministicManaged objects may occasionally leak

Should be explicitly freed using CoEEShutDown

Page 29: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Synthesizing Selected InterfacesmyClass implementing myItf derived from myBase

_myClass: all methods of myItf, myBase, myClass_myBase: all methods of myBasemyItf: all methods of myItf_Object

Additional interfaces implemented on CCWIUnknown

Standard implementation for lifetime management

IDispatchAutomation compatible or internal

ITypeInfo, IProvideClassInfo, IErrorInfo

Page 30: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Exporting a Type Library

Use SDK tool TlbExpType library exported from assembly

Use the TypeLibConverter Class

Leave the conversion to RegAsm utility

Export process involves a lot of conversionsName collisions are solved using name mangling

tlbexp AssemblyName.dll /out:TlbFile

Page 31: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Sample Conversionpublic class MyClass {public void Write(string p, ref string q) {...};public int GetInt() {...};

}

[uuid(…), hidden, dual, odl, nonextensible, oleautomation]interface _MyClass : IDispatch {[propget] HRESULT ToString([out, retval] BSTR* pRetVal);HRESULT Equals([in] VARIANT obj,

[out, retval] VARIANT_BOOL* pRetVal);HRESULT GetHashCode([out, retval] long* pRetVal); HRESULT GetType([out, retval] _Type** pRetVal);HRESULT Write([in] BSTR p, [in, out] BSTR* q);HRESULT GetInt([out, retval] long* pRetVal);

}

[ uuid(...) ]coclass MyClass {[default] interface _MyClass;interface _Object;

}

Page 32: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Special Attributes

Attributes control the conversion process[In], [Out], [MarshalAs(...)]

Parameters, Fields

[GuidAttribute("...")]

Assemblies, classes, interfaces, structures, enumerations, or delegates

Uses Marshal.GenerateGuidForType function

[ComVisibleAttribute(...)]

Individual type or assembly level

Page 33: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Registration (RegAsm)Adds assembly information to the registry

regasm assembly /tlb:tlbfile /regfile:regfile

[HKCR\Namespace.Class] @=„Namespace.Class"

[HKCR\Namespace.Class\CLSID] @="{...}"

[HKCR\CLSID\{...}] @="Namespace.Class"

[HKCR\CLSID\{...}\InprocServer32]

@="C:\WINNT\System32\MSCorEE.dll"

"ThreadingModel"="Both"

"Class"="Namespace.Class"

"Assembly"=„AssemblyName, Ver=1.0.0.0, Loc="""

[HKCR\CLSID\{...}\ProgId] @="Namespace.Class"

Page 34: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Results and ExceptionsYou know: COM uses HRESULTs, .NET exceptions

Can‘t propagate exceptions to unmanaged codeUser defined exception classes define HRESULT

Default is HRESULT of base class

Class NoAccessException : public ApplicationException{

NoAccessException(){

HResult = E_ACCESSDENIED; }

} CMyClass::MethodThatThrows{

NoAccessException e = new NoAccessException(); throw e;

}

Page 35: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Aggregation and Containment Simple requirements to be met

Class must be publicClass must have default constructor

Containment:Simply create instance and delegate calls to it

AggregationJust use CoCreateInstance

COM object‘s IUnknown as outer IUnknown

Queries for unsupported interfaces are delegated backReference counting is done on outer IUnknown

Page 36: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Exposing Inheritance Managed interfaces provide inheritance

Always derive from IUnknown or IDispatchInterface inheritance is flattened

Advantages with versioningUsers of interfaces not effected when base changes Interfaces may be separately attributed

DisadvantageInterfaces cannot be used polymorphically

Page 37: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Converted Inheritance Tree Original managed codeinterface IBase{

void m1(); }

interface IDrvd : IBase{

void m2(); }

class CDrvdImpl : IDrvd{

void m1();void m2();

}

Converted type libraryinterface IBase : IDispatch {

void m1(); }

interface IDrvd : IDispatch {

void m2(); }

interface _CDrvdImpl : IDispatch{

boolean Equals(); // and other methods of objectvoid m1(); void m2();

}

coclass CDrvdImpl{

interface IBase; interface IDerived; interface _CDerivedImpl;interface _Object;

}

Page 38: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Restrictions and Limitations

Parameterized constructors are not exposedAlways uses default constructor

Static methods are not exposed Wrapping with instance method required

Page 39: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Calling Platform Services from .NET

Calling static functions in DLLs

P/Invoke provides servicesLocates implementing DLLLoads DLLFinds function address

Fuzzy name matching algorithm

Pushes arguments on stackPerforms marshallingEnables pre-emptive garbage collectionTransfers control to unmanaged code

Page 40: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Code Samplenamespace HelloWorld{using System;

class MyClass{[dllimport(„user32.dll“, CharSet=CharSet.Ansi)]static extern int MessageBox(int h, string m,

string c, int t);

public static int Main() {return MessageBox(0, "Hello World!", "Caption", 0);

}}

}

Page 41: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Marshalling

Strings are copiedConverted to platform format: ANSI or UnicodeStrings are never copied back – use StringBuilder

Interfaces supportedCannot be used as out parameter

Arrays of primitive types can be used

Custom marshalling using attributes

Page 42: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Showcase for the Standard Marshaller

int SomeFunc( int sel, void* buf, int size);

[DllImport("some.dll")]static extern int SomeFunc(int sel,

[MarshalAs(UnmanagedType.LPArray)] byte[] buf, int size);

[DllImport("some.dll", EntryPoint="SomeFunc")]static extern int SomeFunc_String(int sel,

StringBuilder sb, int size);

[DllImport("some.dll", EntryPoint="SomeFunc")]static extern int SomeFunc_Int(int sel,

ref int i, int size);

Given a method in some DLL

Standard declaration may need special decoding

May use taylored versions

Page 43: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Callbacks Unmanaged code can call back to managed code

Unmanaged parameter is function pointerMust supply parameter as delegateP/Invoke creates callback thunk

Passes address of thunk as callback parameter

Managed Code

.NET Application

Call passes pointer to callback function

Implementation of callback function

Unmanaged Code

DLL

DLL function

Page 44: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Code Samplepublic class EnumReport{

public bool Report(int hwnd, int lParam) { // report the window handle

Console.Write("Window handle is ");Console.WriteLine(hwnd);return true;

}};

public class SampleClass{

delegate bool CallBack(int hwnd, int lParam);

[DllImport("user32")]static extern int EnumWindows(CallBack x, int y);

public static void Main() {

EnumReport er = new EnumReport();CallBack myCallBack = new CallBack(er.Report);EnumWindows(myCallBack, 0);

}}

Page 45: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Security

Suppressing demands for unmanaged code permission

Calling class must be fully trustedUnmanaged code runs with no runtime checks

Any code calling that class must be fully trusted

[SuppressUnmanagedCodeSecurityAttribute()] [dllimport("some.dll")] private static extern int EntryPoint(args);

Page 46: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Component ServicesFundamental building blocks

Just-In-Time activation, synchronization, poolingTransaction processing, shared properties, etc.

Mostly restricted to Windows 2000

COM+ generates and services context object

.NET Client

ContextObject A

ContextObject B

.NET Framework

COM+ Services

Object A(TX required)

Object B(TX supported)

Page 47: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Using COM+ Services

Derive class from System.ServicedComponent

Add attributes to parameterize servicesUse attributes from Microsoft.ComServices namespaceHelper classes: ContextUtil, RegistrationHelper

Use regsvcs to register assembly as serverOr rely on lazy registration

Page 48: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Transactions Sampleusing System;using System.Runtime.CompilerServices;using Microsoft.ComServices;

[assembly:ApplicationName(“TestApp”)]

[Transaction(TransactionOption.Required)]public class Account : ServicedComponent {

[AutoComplete] public void Debit(int amount) {// Any exception thrown here aborts transaction // otherwise transaction commits

}}

class client {static int Main() {

Account accountX = new Account(); accountX.Debit(100); return 0;

}}

Page 49: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Summary

Preserving investments and moving onKeep COM components and enhance using .NETAdd managed components to COM projectsUse Windows Component Services

Prepare COM components for use with .NET

.NET offers maximum transparency

Page 50: COM Interop & P/Invoke - Operating Systems and Middleware Group at

Questions?