Sei sulla pagina 1di 52

.

NET COM Interop


Sam Gentile
.NET Consultant

http://samgentile.com
A Little Bit About Me
 .NET Consultant, Speaker
– Currently working for Microsoft
– Working in managed code for over 2 years with
Microsoft, Groove, Pacific Mindworks, NaviSite
– Designed and implemented
Groove Toolkit for Microsoft Visual Studio .NET
using VSIP, C#, COM Interop, Managed C++, etc.
 .NET Writer, Blogger, Community
– Co-author Wrox Visual C++.NET – Interop, COM
Interop
– Major .NET Blogger at
http://radio.weblogs.com/0105852/
 Contacts
– .NET home at http://www.samgentile.com/
– ManagedCode@attbi.com

http://samgentile.com
What we will cover
 Review of COM and .NET
 Calling COM from .NET
 Calling .NET from COM
 Pitfalls and Workarounds

http://samgentile.com
Session Prerequisites
 This is a programmer group
 You know some C++ or VB for COM side
 You know some C# for .NET side
 You have a familiarity with COM: Cannot
learn COM here
 You have familiarity with .NET and CLR; I
will review concepts directly relevant to
Interop
http://samgentile.com
So Why This Presentation?
 There are over 1 Billion lines of existing
legacy COM
 Most companies will not start with
managed code right away
– New skill sets to learn
– Preserve existing investment in components
– Economy
 Transition to .NET will be a lasting process
 Big opportunities for you

http://samgentile.com
Demonstrations
 Generating Interops (RCWs) with VS.NET
and tlbimp
 Peering Inside Interops
 Using tlbexp to generate Interops and
Implementing Class Interfaces

http://samgentile.com
Agenda
 Review of COM and .NET
 Calling COM from .NET
 Calling .NET from COM
 Pitfalls and Workarounds

http://samgentile.com
COM Is…
 Interface based
 Separate interface and implementation
 Dynamic runtime linking
 Binary Standard Object Model
 Language neutral (in theory)
 Deterministic

http://samgentile.com
.NET
 Metadata
 Virtualization of contracts
 Runtime provides services
 Virtualization of types (CTS)
 Versioning
 Deterministic

http://samgentile.com
Review of .NET Concepts
 Managed code
 Metadata
 Assemblies
 Strong names
 GAC
 Reflection
 Custom Attributes

http://samgentile.com
Bridging Different Worlds
 Unmanaged Code Managed Code
 Type libraries  Meta data
 Immutable types  Resilient bind
 DLL issues  Assemblies
 Interface based  Object based
 HRESULTS  Exceptions
 GUIDS  Strong names

http://samgentile.com
Agenda
 Review of COM and .NET
 .NET to COM
 COM to .NET
 Windows Forms

http://samgentile.com
Need for RCWs
 COM types defined in type library (and IDL)
 .NET types in assemblies and have metadata
 Need to import types and generate metadata in
form of Interop Assembly
 Need proxy to transparently handle .NET to
COM transition
 Runtime Callable Wrapper (RCW)
 Marshal between managed and COM

http://samgentile.com
The Role of the RCW
 Marshal calls back and forth (proxy)
 “Fool” .NET clients
 Maintain COM identity and lifetime
 Implement low-level COM Interfaces
 .NET class type dynamically created by
CLR based on Interop Assembly
 Created when reference to COM object
marshaled across MSCOREE boundary
http://samgentile.com
Creating an RCW
 Visual Studio .NET Add COM Reference
– Easiest and least flexible
– Type lib provides definition of types
 Framework SDK tlbimp.exe
 System.Runtime.InteropServices.TypeLib
Converter

http://samgentile.com
Using VS.NET
 Add COM Reference – equivalent to:
– Tlbimp InputFile /out:Interop.LibraryName.dll /namespace:LibraryName
/sysarray

http://samgentile.com
Using tlbimp.exe
 More flexible and don’t need VS.NET
 Command line tool generates .NET
Interop Assembly
 Reads type info from TLB and
generates .NET metadata
 Simplest form: tlbimp foo.dll
 Can specify name of output assembly with
/out - important
http://samgentile.com
Important tlbimp options
 /sysarray converts SAFEARRAYS to
System.Array
 /ref to resolve references is key
 /delaysign option
 /publickey, /keyfile, /keycontainer affect
signing
 /primary will be discussed soon

http://samgentile.com
Demo 1
Generating Interops (RCWs) with
VS.NET and tlbimp
Using Interops and RCWs from C#
clients

http://samgentile.com
Interop Assemblies
 Generated by Type Lib Importer
 Metadata that resolves calls and let
runtime create an RCW
 Another “view” into same COM types
 Underlying COM Object does not change
 Mostly metadata

http://samgentile.com
Look Inside at Types Generated
Generated Managed Type Meaning in Life
Tlbimp generates a type that has the same
CAdd name as the [default] interface minus the
“I-” prefix. Type creatable but you will only
be able to access types explicitly defined
by this interface.
Tlbimp always generates managed
IAdd eqivalents for each interface found in TLB.
Of course, these are NOT creatable.

For every co-class listed in the IDL library


CAddClass section there is a .NET Managed Class
Type. In other words, class CAdd becomes
CAddClass. These .NET types are directly
creatable and support the members of each
and every implemented COM interface.

http://samgentile.com
COM value type COM reference type System type
bool bool * System.Int32
char, small char *, small * System.SByte
short short * System.Int16
long, int long *, int * System.Int32
Hyper hyper * System.Int64
unsigned char, byte unsigned char *, byte System.Byte
*
wchar_t, unsigned wchar_t *, unsigned System.UInt16
short short *
unsigned long, unsigned long *, System.UInt32
unsigned int unsigned int *
float float * System.Single
double double * System.Double
void * void ** System.IntPtr
HRESULT HRESULT * System.Int16 or
http://samgentile.com
System.IntPtr
Type Conversion Specifics
 DATE System.DateTime
 BSTR System.String
 SafeArray(int) int[]
 OLECOLOR uint
 CURRENCY System.Decimal
 VARIANT System.Object
 Interface interface IMyInterface
IMyInterface
 coclass Bar class Bar
 IEnumVariant IEnumerator
http://samgentile.com
More Marshaling
 Isomorphic (Blittable) Types
– Integers, Float Values
 Non-isomorphic Types
– Booleans, Chars, Strings, Arrays, Objects
 Copying vs. Pinning
– Isomorphic Types are pinned
– Non-isomorphic are copied

http://samgentile.com
Demo 2
Peering Inside Interops

http://samgentile.com
Primary Interop Assemblies
 Every time someone generates Interops
creates distinct identity, version
 Want single, “blessed” managed identity
– Digitally signed by publisher
– Strongly named
– Marked primary
– Put in the GAC
 Created with tlbimp /primary

http://samgentile.com
Agenda
 Review of COM and .NET
 .NET to COM
 COM to .NET
 Pitfalls and Workarounds

http://samgentile.com
Why?
 The world is filled with unmanaged clients and
hosts (and will be for quite a while…)
– Windows Shell
– Internet Explorer
– Office XP
– VB 6.0
 Managed objects in unmanaged hosts use Interop
 You can easily host .NET objects from both
unmanaged and managed hosts

http://samgentile.com
COM to .NET Interop

Common Language Traced


IUnknown Runtime Reference
COM Client IDispatch
IMyInterface
COM
Callable Object
Wrapper

Reference IMyInterface
Counted
Client

http://samgentile.com
COM Callable Wrapper
 Created when marshal ref to CLR object
across boundary
 Proxy to transform .NET to COM
 Unmanaged COM object holding one
reference to managed object
 Single CCW shared among multiple COM
clients for given COM type
– Insures identity
– No matter how object created

http://samgentile.com
Role of the CCW
 Fool COM clients
 Transform .NET data types into COM
equivalents (marshaling)
 Canned implementation of standard COM
Interfaces
 Proxying custom interfaces
 Maintaining object lifetime

http://samgentile.com
Generating COM Type
Definitions
1. Tlbexp.exe command line tool
2. Regasm.exe command line tool
3. VS.NET Project Properties (calls 1,2)
4. Programmatically using
TypeLibConverter
5. Regsvcs.exe command line tool

http://samgentile.com
Using tlbexp.exe
 Command line tool
 Very few options needed because
attributes
 Most options useless
 Syntax: tlbexp.exe foo.dll
 /out flag lets you control name

http://samgentile.com
Registering with regasm
 Command line utility
 Creates all needed COM Registry settings
 With /tlb also generates and registers type
lib
 Result of /tlb is a .tlb containing IDL defs
 Default value for InProcServer32 key is
MSCOREE.DLL

http://samgentile.com
Registry Settings by Regasm
 HKEY_CLASSES_ROOT\ProgID\[default]=“NamespaceQualifiedClassName”
 HKEY_CLASSES_ROOT\ProgID\CLSID\[default]=“{CLSID}”
 HKEY_CLASSES_ROOT\CLSID\{CLSID}\
[default]=“NamespaceQualifiedClassName”
 HKEY_CLASSES_ROOT\CLSID\{CLSID}\ImplementedCategories\
– {62C8FE65-4EBB-45E7-B440-6E39B2CDBF29}
 HKEY_CLASSES_ROOT\CLSID\{CLSID}\ InprocServer32\[default]=
– “WindowsaSystemDirectory\mscoree.dll”
 HKEY_CLASSES_ROOT\CLSID\
{CLSID}\InprocServer32\Assembly=“FullAssemblyName”
 HKEY_CLASSES_ROOT\CLSID\
{CLSID}\InprocServer32\Class=“NamespaceQualifiedClassName”
 HKEY_CLASSES_ROOT\CLSID\{CLSID}\InprocServer32\RuntimeVersion=“Version”
 HKEY_CLASSES_ROOT\CLSID\{CLSID}\InprocServer32\ThreadingModel=“Both”
 HKEY_CLASSES_ROOT\CLSID\{CLSID}\ProgID=“ProgID”

http://samgentile.com
Finding and Loading the Interop
 DllGetClassObject called, CLR checks
Class value
 Fusion finds Assembly by normal rules
 Must be placed where Fusion can find it
 GAC is recommended place since shared
anyhow
 /codebase can be used for development
only
http://samgentile.com
.NET Metadata to COM Types
 DATE System.DateTime
 BSTR System.String
 Safearray(int) int[]
 OLECOLOR System.Drawing.Color
 DECIMAL System.Decimal
 VARIANT System.Object
 Interface interface IMyInterface
IMyInterface
 Class CMyClass coclass CMyClass
 IEnumVariant IEnumerator
http://samgentile.com
Controlling Translation
 ComVisible attribute
 InterfaceTypeAttribute
 ClassInterfaceAttribute
 StructLayoutAttribute
 GuidAttribute
 ProgIdAttribute

http://samgentile.com
Understanding the Class
Interface

http://samgentile.com
Understanding the .NET Class
Interface
 You may be surprised by what you get by
default from export!
 Empty [default] dual interface
 exporter generates empty IDispatch-
derived interfaces named _CoClassname
to “preserve identity of .NET class Types.”
 Tlbexp will always generate an
AutoDispatch class interface unless you
say differently
http://samgentile.com
The Case Against Class
Interfaces
 MSFT: Avoid and use ClassInterface.None
 Why evil? Dreaded versioning problem
 .NET interface can change breaking COM
 Empty AutoDispatch interface generated and
clients must access via late binding only
 EX: COM class implements .NET interface with
member containing a MyClass parameter
– Exporter can match the _MyClass parameter in
COM’s TLB to original MyClass .NET definition
– Enabled by special IDL custom attribute

http://samgentile.com
Recommended Approach
 Microsoft recommends defining and
implementing real .NET interface
 And ClassInterfaceType.None
 Generates real COM interface that be
accessed through a v-table
 Let’s see how in the following demo

http://samgentile.com
Demo 3
Using tlbexp to generate Interops
Regasm
Class Interfaces

http://samgentile.com
Agenda
 Review of COM and .NET
 .NET to COM
 COM to .NET
 Pitfalls and Workarounds

http://samgentile.com
Determinstic Finalization
 BIG problem in REAL COM applications – spent months on this at one
company
 Problem: Release calls to COM Interface Pointers are non-deterministic
because COM object release not released until RCW itself is garbage
collected (whenever) and COM wants to be deterministic
 Also CCW holds rooted reference to underlying CLR object & prevents GC
as long as at least one outstanding COM Interface Pointer
 Not good because of performance reasons and possible semantics of object
model require certain objects to be released at certain times (i.e.
Connection Points)
 Solution: call the Marshal::ReleaseComObject method in the
System::Runtime::InteropServices namespace for each COM interface.
 Solution: Convert rooted ref inside CCW to weak with
Marshal.ChangeWrapperHandleStrength
 Is this a Design Flaw or a COM Cycle Issue?
 See my essays Is COM Interop Fundamentally Flawed? And Part 3 - A
Solution and discussion

http://samgentile.com
The Problem
 COM objects wrapped in RCWs are not reference-
counted based on number of .NET clients
 Instead, any COM interface obtained through RCW has
its reference count incremented once
 When RCW garbage collected, its finalizer calls
IUnknown.Release on every cached interface pointer
 Marshal.ReleaseComObject does deterministic release –
release now
 This can become very messy quickly
 If intermediate RCWs are created when using an RCW,
may have to call ReleaseComObject more than once to
clean up everything

http://samgentile.com
Solutions
 Implement IDisposable pattern
– Helper class per COM object that uses types
defined by the Interop Assemblies
– Helper class per COM object that uses
another helper class which uses raw UCOM
(ex: raw connection points)
 Convert rooted ref inside CCW to weak
with
Marshal.ChangeWrapperHandleStrength
http://samgentile.com
Case 1
 In EventHandlers:
Marshal.ReleaseComObject(interface);
And:
 public new Dispose()
 {
 // unsubscribe from event
 m_foo.OnSomething -= delegate(eventHandler);
 Marshal.ReleaseComObject(m_foo);
 m_foo = null;
 }

http://samgentile.com
Case 2
 In event handlers, create raw helper class and delegate calls to it
(i.e. Advise)
 Helper class uses Raw Unmanaged COM semantics and UCOM
classes
 private UCOMIConnectionPoint m_ConnectionPoint = null;
 ...
 UCOMIConnectionPointConatiner cpc =
 (UCOMIConnectionPointContainer)interface;
 cpc.FindConnectionPoint(ref iiid, out m_ConnectionPoint);
 m_ConnectionPoint.Advise(...);
 For more see
http://radio.weblogs.com/0111019/stories/2002/08/05/connectionPoi
ntBasedEventHandlingBetweenComAndnet.html

http://samgentile.com
Session Summary
 All your existing COM investments
preserved and usable
 Prepare COM components for use with
.NET
 Interop works…
 …But is hard in many non-trivial cases

http://samgentile.com
Resources
 .NET and COM: The Complete Interoperability Guide, Adam Nathan,
Microsoft, Sam’s Publishing ISBN 067232170x
 Visual C++.NET: A Primer for C++ Developers, Corera, Fraser,
Gentile, etc. Wrox. Chapters 7-8, ISBN 1861005962
 COM and .NET Interoperability, Andrew Troelsen, APress,
1590590112
 My .NET Blog http://radio.weblogs.com/0105852/
 My Web Site http://www.samgentile.com/
 My Friends
– Peter Drayton http://www.razorsoft.net/weblog/index.html
– Tomas Restapo http://www.winterdom.com/weblog/
– Don Box http://www.gotdotnet.com/team/dbox/spoutlet.aspx
– Chris Sells http://www.sellsbrothers.com/
– Ingo Rammer http://www.dotnetremoting.cc/DotNetCentric/
– Paresh Suthar http://radio.weblogs.com/0111019/

http://samgentile.com
Questions

http://samgentile.com

Potrebbero piacerti anche