COM Interop & P/Invoke .NET and the Old World Objectives - - PowerPoint PPT Presentation

com interop p invoke
SMART_READER_LITE
LIVE PREVIEW

COM Interop & P/Invoke .NET and the Old World Objectives - - PowerPoint PPT Presentation

COM Interop & P/Invoke .NET and the Old World Objectives Introduction to interoperation between .NET and COM COM and .NET .NET and platform services Contents Section 1: Overview Section 2: Calling COM Services from


slide-1
SLIDE 1

COM Interop & P/Invoke

.NET and the Old World

slide-2
SLIDE 2

Objectives

Introduction to interoperation between

.NET and COM COM and .NET .NET and platform services

slide-3
SLIDE 3

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

slide-4
SLIDE 4

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

slide-5
SLIDE 5

What is different in the two Worlds?

Managed Code vs. Unmanaged Code

Lifetime management Metadata

Common Type System Inheritance concept Threading model Error handling mechanisms Registration

slide-6
SLIDE 6

Calling COM Services from .NET

Metadata for COM class must be available

Can be generated from Type Library Can declare Custom Wrapper

Use COM class like .NET class Early and late bound activation COM component must be registered locally

slide-7
SLIDE 7

Early Bound Activation

Instantiate like creating a .NET object Metadata must be available at compile time

Must be referenced in development environment

At runtime, Metadata and COM library must be available

COMLib.COMClass COMLib.COMClass aCOMObject; aCOMObject; aCOMObject aCOMObject = new = new COMLib.COMClass; COMLib.COMClass;

slide-8
SLIDE 8

Runtime Callable Wrappers

Preserving object identity Maintaining object lifetime Proxying interfaces Marshalling method calls Consuming selected interfaces .NET Object COM Object RCW

IUnknown IDispatch IIfc IIfc

slide-9
SLIDE 9

Consuming Selected Interfaces

ISupportErrorInfo

ISupportErrorInfo

Additional information with exceptions

IProvideClassInfo

IProvideClassInfo

Typed wrapper

ITypeInfo

ITypeInfo

TlbImp

TlbImp converts references to System.Type System.Type

slide-10
SLIDE 10

Identity and Lifetime Control

COM lifetime control is wrapped by RCW COM object released when RCW garbage collected Non-deterministic finalization issue

COMLib.COMClass COMLib.COMClass aCOMObject; aCOMObject; aCOMObject aCOMObject = new = new COMLib.COMClass(); COMLib.COMClass(); aCOMObject.SomeFunc(); aCOMObject.SomeFunc(); Marshal.ReleaseComObject(aCOMObject); Marshal.ReleaseComObject(aCOMObject);

slide-11
SLIDE 11

Converting Type Library to Metadata

Use 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 preserved

IDL: IDL: [custom(„FE42746F-...-AC...84178”, “Value”)] [custom(„FE42746F-...-AC...84178”, “Value”)] .NET: .NET: [IdlAttribute(„FE42746F-...-AC...84178”, “Value”)] [IdlAttribute(„FE42746F-...-AC...84178”, “Value”)]

slide-12
SLIDE 12

Conversions by TlbImp 1/2

Library level

Library to namespace

Module is converted to class

Constants within module to constants within that class Module functions to static members of the class

library library COMLib { COMLib { interface Widget {}; interface Widget {}; coclass coclass Slingshot {}; Slingshot {}; } namespace namespace COMLib { COMLib { interface Widget {}; interface Widget {}; class Slingshot {}; class Slingshot {}; } custom(0F21F359-AB84-41e8-9A78-36D110E6D2F9, custom(0F21F359-AB84-41e8-9A78-36D110E6D2F9, „MyNamespace.Class") „MyNamespace.Class")

slide-13
SLIDE 13

Conversions by TlbImp 2/2

Interfaces

Base interfaces IUnknown and IDispatch are stripped

Type definitions are not imported

Imported as the underlying types

Properties

Generates corresponding get

get and set set

Events

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

slide-14
SLIDE 14

Marshalling

Isomorphic Types

Integer, Float Values

Non-isomorphic Types

Booleans, Chars, Strings, Arrays, Objects

Copying vs. Pinning

Isomorphic Types are pinned Non-Isomorphic Types are copied Watch out with Unicode Strings!

Passing by value actually passes a reference! Passing by reference creates new String

slide-15
SLIDE 15

Marshalling a Union

Use attributed struct in .NET

StructLayout

StructLayout attribute for

Sequential

Sequential layout – is a regular structure

Default Union

Union layout

Explicit

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

slide-16
SLIDE 16

Inheritance

COM uses containment/aggregation .NET adds implementation inheritance Mixed-mode objects

Managed objects can derive from COM objects

Must have metadata available Must be instantiatable Must be aggregatable

Interfaces can be inherited

IUnknown, IDispatch derivation is removed

slide-17
SLIDE 17

Calling an COM Server

namespace CallingCOMServer namespace CallingCOMServer { using System; using System; using COMServerLib; using COMServerLib; public class DotNET_COMClient public class DotNET_COMClient {... {... public static int public static int Main(string[] args) Main(string[] args) { MyCOMServer myS MyCOMServer myS = new MyCOMServer(); = new MyCOMServer(); return return (myS.Add (myS.Add (17,4)); (17,4)); } } }; };

slide-18
SLIDE 18

Late Bound Activation

Accomplished by Reflection API

No difference whether COM or .NET object

Type can be obtained from ProgID or ClsID

InvokeMember

InvokeMember to access methods and properties

Metadata is not needed, but useful

COM object is wrapped by __ComObject

slide-19
SLIDE 19

Late Bound Call to COM Server

namespace LateBoundClient namespace LateBoundClient { using System.Reflection; using System.Reflection; ... ... Type typ; Type typ; Object Object obj;

  • bj;

Object[] prms Object[] prms = new = new Object[2]; Object[2]; int int r; r; typ typ = Type.GetTypeFromProgID(„MyLib.MyServer"); = Type.GetTypeFromProgID(„MyLib.MyServer");

  • bj
  • bj = Activator.CreateInstance(typ);

= Activator.CreateInstance(typ); prms[0] = 10; prms[0] = 10; prms[1] = 150; prms[1] = 150; r = (int)typ.InvokeMember(„aMethod", r = (int)typ.InvokeMember(„aMethod", BindingFlags.InvokeMethod, null, obj, prms); BindingFlags.InvokeMethod, null, obj, prms); ... ... }

slide-20
SLIDE 20

Calling an Automation Server

namespace AutomationClient namespace AutomationClient { using EmotionalTulip; using EmotionalTulip; using System.Reflection; using System.Reflection; ... ... TulipApplication tulipApp = new TulipApplication(); TulipApplication tulipApp = new TulipApplication(); Type t Type t = tulipApp.GetType(); tulipApp.GetType(); Object[] prms Object[] prms = new Object[1]; = new Object[1]; prms[0] = true; prms[0] = true; t.InvokeMember("Visible", t.InvokeMember("Visible", BindingFlags.SetProperty, BindingFlags.SetProperty, null, tulipApp, prms); null, tulipApp, prms); t.InvokeMember("Exit", t.InvokeMember("Exit", BindingFlags.InvokeMethod, BindingFlags.InvokeMethod, null, tulipApp, null); null, tulipApp, null); ... ... }

slide-21
SLIDE 21

Threading

Most COM objects are single threaded .NET thread must initialize COM apartment

Deferred initialization Initialized either as MTA or STA

Runtime provides transparent use of COM threads

Access apartment threaded objects through proxy Can avoid proxy by setting apartment state of thread

slide-22
SLIDE 22

Let the runtime initialize the default MTA Setting ApartmentState explicitly eliminates proxy

Do before the object is created!

Using ApartmentState

using System.Threading; using System.Threading; using APTOBJLib; using APTOBJLib; AptSimple AptSimple obj

  • bj = new AptSimple

= new AptSimple (); ();

  • bj.Counter
  • bj.Counter = 1;

= 1; using System.Threading; using System.Threading; using APTOBJLib; using APTOBJLib; Thread.CurrentThread.ApartmentState Thread.CurrentThread.ApartmentState = = ApartmentState.STA; ApartmentState.STA; AptSimple AptSimple obj

  • bj = new AptSimple();

= new AptSimple();

  • bj.Counter
  • bj.Counter = 1;

= 1;

slide-23
SLIDE 23

Results and Exceptions

COM reports errors via result code

.NET methods throws exceptions Runtime manages transition

HRESULT specifies exception class Extended information via IErrorInfo

COM object should implement interface

ErrorCode

ErrorCode, HelpLink HelpLink, Message Message

Source

Source, StackTrace StackTrace, TargetSite TargetSite

PreserveSigAttribute

PreserveSigAttribute in custom wrapper

Suppresses translation to exception

slide-24
SLIDE 24

Design for Interoperability

Provide and register Type Libraries Use Automation Compliant Data Types Use Chunky Calls

Marshalling may be costly

Explicitly Free External Resources Avoid Using Members of System.Object

Object, Equals, Finalize, GetHashCode, GetType MemberwiseClone and ToString

slide-25
SLIDE 25

Restrictions and Limitations

void*

void* parameters need marshalling

Success HRESULTS

HRESULTS cannot be distinguished

Failure HRESULT

HRESULT do raise exceptions

Success code don‘t

Typedef

Typedef do not get through

Variable length arrays cannot be imported

is imported as

HRESULT DoSomething(int HRESULT DoSomething(int cb, [in] byte buf[]); cb, [in] byte buf[]); public void DoSomething(int public void DoSomething(int cb, ref Byte buf); cb, ref Byte buf);

slide-26
SLIDE 26

Calling .NET Services from COM

Use .NET class like COM class

Type and methods must be public

Early and late bound activation Convert Metadata to Type Library Wrapper of .NET component must be registered

Can use RegAsm

RegAsm tool

slide-27
SLIDE 27

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

IUnknown IDispatch IIfc IIfc

slide-28
SLIDE 28

Identity and Lifetime Control

Single CCW for .NET class insures identity

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

Each interface of the CCW is referenced counted

No reference counting on the managed object

Managed objects lives at least while the CCW lives

But finalization is undeterministic Managed objects may occasionally leak

Should be explicitly freed using CoEEShutDown

CoEEShutDown

slide-29
SLIDE 29

Synthesizing Selected Interfaces

myClass

myClass implementing myItf myItf derived from myBase

myBase

_myClass

_myClass: all methods of myItf, myBase, myClass

_myBase

_myBase: all methods of myBase

myItf

myItf: all methods of myItf

_Object

_Object

Additional interfaces implemented on CCW

IUnknown

Standard implementation for lifetime management

IDispatch

Automation compatible or internal

ITypeInfo, IProvideClassInfo, IErrorInfo

slide-30
SLIDE 30

Exporting a Type Library

Use SDK tool TlbExp

Type library exported from assembly

Use the TypeLibConverter

TypeLibConverter Class

Leave the conversion to RegAsm

RegAsm utility

Export process involves a lot of conversions

Name collisions are solved using name mangling

tlbexp tlbexp AssemblyName.dll AssemblyName.dll /out:TlbFile /out:TlbFile

slide-31
SLIDE 31

Sample Conversion

public public class MyClass class MyClass { public public void Write(string void Write(string p, ref p, ref string string q) q) {...}; {...}; public public int int GetInt() {...}; GetInt() {...}; } [uuid(…), hidden, dual, odl, nonextensible, oleautomation] [uuid(…), hidden, dual, odl, nonextensible, oleautomation] interface _MyClass interface _MyClass : IDispatch { : IDispatch { [propget] HRESULT ToString([out, retval] BSTR* pRetVal); [propget] HRESULT ToString([out, retval] BSTR* pRetVal); HRESULT Equals([in] VARIANT obj, HRESULT Equals([in] VARIANT obj, [out, retval] [out, retval] VARIANT_BOOL* pRetVal); VARIANT_BOOL* pRetVal); HRESULT GetHashCode([out, retval] long* pRetVal HRESULT GetHashCode([out, retval] long* pRetVal);

);

HRESULT GetType([out, retval] _Type** pRetVal); HRESULT GetType([out, retval] _Type** pRetVal); HRESULT Write([in] BSTR p, [in, out] BSTR* q); HRESULT Write([in] BSTR p, [in, out] BSTR* q); HRESULT GetInt([out, retval] long* pRetVal); HRESULT GetInt([out, retval] long* pRetVal); } [ uuid(...) ] [ uuid(...) ] coclass coclass MyClass MyClass { [default] interface _MyClass; [default] interface _MyClass; interface interface _Object; _Object; }

slide-32
SLIDE 32

Special Attributes

Attributes control the conversion process

[In], [Out], [MarshalAs(...)]

[In], [Out], [MarshalAs(...)]

Parameters, Fields

[GuidAttribute("...")]

[GuidAttribute("...")]

Assemblies, classes, interfaces, structures, enumerations,

  • r delegates

Uses Marshal.GenerateGuidForType

Marshal.GenerateGuidForType function

[ComVisibleAttribute(...)]

[ComVisibleAttribute(...)]

Individual type or assembly level

slide-33
SLIDE 33

Registration (RegAsm)

Adds assembly information to the registry

regasm

regasm assembly /tlb: /tlb:tlbfile /regfile /regfile:regfile [HKCR\ [HKCR\Namespace.Class Namespace.Class] @=„ ] @=„Namespace.Class Namespace.Class" [HKCR\ [HKCR\Namespace.Class Namespace.Class\CLSID] @="{...}" \CLSID] @="{...}" [HKCR\CLSID\{...}] @=" [HKCR\CLSID\{...}] @="Namespace.Class Namespace.Class" [HKCR\CLSID\{...}\InprocServer32] [HKCR\CLSID\{...}\InprocServer32] @="C:\WINNT\System32\MSCorEE.dll" @="C:\WINNT\System32\MSCorEE.dll" "ThreadingModel"="Both" "ThreadingModel"="Both" "Class"=" "Class"="Namespace.Class Namespace.Class" "Assembly"=„ "Assembly"=„AssemblyName AssemblyName, Ver=1.0.0.0, Loc=""" , Ver=1.0.0.0, Loc=""" [HKCR\CLSID\{...}\ProgId] @=" [HKCR\CLSID\{...}\ProgId] @="Namespace.Class Namespace.Class"

slide-34
SLIDE 34

Results and Exceptions

You know: COM uses HRESULTs, .NET exceptions Can‘t propagate exceptions to unmanaged code

User defined exception classes define HRESULT

Default is HRESULT of base class

Class NoAccessException Class NoAccessException : : public ApplicationException public ApplicationException { { NoAccessException() NoAccessException() { HResult HResult = E_ACCESSDENIED; = E_ACCESSDENIED; } } } } CMyClass::MethodThatThrows CMyClass::MethodThatThrows { { NoAccessException NoAccessException e = e = new NoAccessException(); new NoAccessException(); throw e; throw e; }

slide-35
SLIDE 35

Aggregation and Containment

Simple requirements to be met

Class must be public Class must have default constructor

Containment:

Simply create instance and delegate calls to it

Aggregation

Just use CoCreateInstance

COM object‘s IUnknown as outer IUnknown

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

slide-36
SLIDE 36

Exposing Inheritance

Managed interfaces provide inheritance

Always derive from IUnknown or IDispatch Interface inheritance is flattened

Advantages with versioning

Users of interfaces not effected when base changes Interfaces may be separately attributed

Disadvantage

Interfaces cannot be used polymorphically

slide-37
SLIDE 37

Converted Inheritance Tree

Original managed code

interface IBase interface IBase { { void m1(); void m1(); } } interface IDrvd interface IDrvd : IBase : IBase { { void m2(); void m2(); } } class CDrvdImpl class CDrvdImpl : IDrvd : IDrvd { void m1(); void m1(); void m2(); void m2(); } }

Converted type library

interface interface IBase IBase : IDispatch : IDispatch { { void m1(); void m1(); } } interface interface IDrvd IDrvd : IDispatch : IDispatch { { void m2(); void m2(); } } interface interface _CDrvdImpl _CDrvdImpl : IDispatch : IDispatch { { boolean boolean Equals(); Equals(); // and other methods of object // and other methods of object void m1(); void m1(); void m2(); void m2(); } coclass coclass CDrvdImpl CDrvdImpl { interface IBase; interface IBase; interface IDerived; interface IDerived; interface _CDerivedImpl; interface _CDerivedImpl; interface _Object; interface _Object; } }

slide-38
SLIDE 38

Restrictions and Limitations

Parameterized constructors are not exposed

Always uses default constructor

Static methods are not exposed

Wrapping with instance method required

slide-39
SLIDE 39

Calling Platform Services from .NET

Calling static functions in DLLs P/Invoke provides services

Locates implementing DLL Loads DLL Finds function address

Fuzzy name matching algorithm

Pushes arguments on stack Performs marshalling Enables pre-emptive garbage collection Transfers control to unmanaged code

slide-40
SLIDE 40

Code Sample

namespace namespace HelloWorld HelloWorld { using using System; System; class class MyClass MyClass { [dllimport(„user32.dll“, CharSet=CharSet.Ansi)] [dllimport(„user32.dll“, CharSet=CharSet.Ansi)] static static extern int extern int MessageBox(int MessageBox(int h, string h, string m, m, string string c, int c, int t); t); public public static static int int Main() Main() { return return MessageBox(0, "Hello MessageBox(0, "Hello World!", "Caption", 0); World!", "Caption", 0); } } }

slide-41
SLIDE 41

Marshalling

Strings are copied

Converted to platform format: ANSI or Unicode Strings are never copied back – use StringBuilder

StringBuilder

Interfaces supported

Cannot be used as out parameter

Arrays of primitive types can be used Custom marshalling using attributes

slide-42
SLIDE 42

Showcase for the Standard Marshaller

int int SomeFunc SomeFunc( int ( int sel, void* buf, int sel, void* buf, int size); size); [DllImport("some.dll")] [DllImport("some.dll")] static static extern int extern int SomeFunc SomeFunc(int (int sel, sel, [MarshalAs(UnmanagedType.LPArray)] byte[] buf, [MarshalAs(UnmanagedType.LPArray)] byte[] buf, int int size); size);

[DllImport("some.dll", EntryPoint="SomeFunc")]

DllImport("some.dll", EntryPoint="SomeFunc")] static static extern int extern int SomeFunc_String SomeFunc_String(int (int sel, sel, StringBuilder StringBuilder sb, int sb, int size); size); [DllImport("some.dll", EntryPoint="SomeFunc")] [DllImport("some.dll", EntryPoint="SomeFunc")] static static extern int extern int SomeFunc_Int SomeFunc_Int(int (int sel, sel, ref ref int int i, int i, int size); size);

Given a method in some DLL Standard declaration may need special decoding May use taylored versions

slide-43
SLIDE 43

Callbacks

Unmanaged code can call back to managed code

Unmanaged parameter is function pointer Must supply parameter as delegate P/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

slide-44
SLIDE 44

Code Sample

public public class class EnumReport EnumReport { public public bool bool Report(int Report(int hwnd, int hwnd, int lParam) lParam) { // report { // report the the window window handle handle Console.Write("Window Console.Write("Window handle is handle is "); "); Console.WriteLine(hwnd); Console.WriteLine(hwnd); return return true; true; } }; }; public public class class SampleClass SampleClass { delegate delegate bool bool CallBack(int CallBack(int hwnd, int hwnd, int lParam); Param); [DllImport("user32")] [DllImport("user32")] static static extern int extern int EnumWi EnumWindows(CallBack ndows(CallBack x, int x, int y); y); public public static static void void Main() Main() { EnumReport EnumReport er = new er = new EnumReport(); numReport(); CallBack CallBack myCallBack myCallBack = = new new CallBack(er.Report); CallBack(er.Report); EnumWindows(myCallBack, 0); EnumWindows(myCallBack, 0); } }

slide-45
SLIDE 45

Security

Suppressing demands for unmanaged code permission Calling class must be fully trusted

Unmanaged code runs with no runtime checks

Any code calling that class must be fully trusted

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

slide-46
SLIDE 46

Component Services

Fundamental building blocks

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

Mostly restricted to Windows 2000 COM+ generates and services context object .NET Client Context Object A Context Object B .NET Framework COM+ Services Object A

(TX required)

Object B

(TX supported)

slide-47
SLIDE 47

Using COM+ Services

Derive class from System.ServicedComponent

System.ServicedComponent

Add attributes to parameterize services

Use attributes from Microsoft.ComServices

Microsoft.ComServices namespace

Helper classes: ContextUtil

ContextUtil, RegistrationHelper RegistrationHelper

Use regsvcs

regsvcs to register assembly as server

Or rely on lazy registration

slide-48
SLIDE 48

Transactions Sample

using using System; System; using System.Runtime.CompilerServices; using System.Runtime.CompilerServices; using Microsoft.ComServices; using Microsoft.ComServices; [assembly:Application [assembly:ApplicationName(“TestApp”)] Name(“TestApp”)] [Transaction(Transact [Transaction(TransactionOption.Required)] ionOption.Required)] public class Account public class Account : ServicedComponent : ServicedComponent { { [AutoComplete] [AutoComplete] public public void Debit(int void Debit(int amount) { amount) { // Any exception thrown // Any exception thrown here aborts transaction here aborts transaction // otherwise transaction commits // otherwise transaction commits } } } class client { class client { static int static int Main() Main() { Account accountX Account accountX = new Account(); = new Account(); accountX.Debit(100); accountX.Debit(100); return 0; return 0; } } }

slide-49
SLIDE 49

Summary

Preserving investments and moving on

Keep COM components and enhance using .NET Add managed components to COM projects Use Windows Component Services

Prepare COM components for use with .NET .NET offers maximum transparency

slide-50
SLIDE 50

Questions?