2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of...

75
Understanding and Using COM Threading Model Recording Engine, DDR Team James S. Hsieh [email protected] n Inconvenient Truth and Nightmare of Marshalling

Transcript of 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of...

Page 1: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Understanding and Using

COM Threading Model

Recording Engine, DDR TeamJames S. Hsieh

[email protected]

An Inconvenient Truth and Nightmare of Marshalling

Page 2: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

1. COM Threading Models

2. Mixed Model Development

3. COM Interface Marshalling and Unmarshlling

4. COM Client Case Studies

5. Inside Standard Marshalling

6. COM Server Side Case Studies

7. Conclusion

Agenda

Page 3: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

1. COM Threading Models

1. COM Threading Models

2. Mixed Model Development

3. COM Interface Marshalling and Unmarshlling

4. COM Client Case Studies

5. Inside Standard Marshalling

6. COM Server Side Case Studies

7. Conclusion

Page 4: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

What is COM: Component Object Model Technologies?

Component Object Model (COM) is a Microsoft centric interface standard for software componentry introduced by Microsoft in 1993. OLE 1991 COM+ 2000

COM as an object framework

1. Programming Language Independent Object Model (IDL, Binary level layout)

2. Abstraction and Object Independent (Interface and Reference Counting)

3. Reflection (IDL, Type Library, and Automation)

4. Interprocess Communication , Location Transparency(IDL, Marshalling, Proxy and Stub, ORPC)

5. Type and Object Binding (Moniker)

6. Dynamic Object Creation, Serialization

COM Client needs know

.NET Managed Code

C#, VB .NET…

Runtime Callable Wrapper

Native CodeC/C++…

COMBinary

Protocols

Native Code C/C++…

COM Callable Wrapper

.NET Managed Code

C#, VB .NET…

Implemented byInvoker COM Object framework

Page 5: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

What is Thread Safety?

Thread Safety

Thread safety is a computer programming concept applicable in the context of multi-threaded programs. A piece of code is thread-safe if it functions correctly during simultaneous execution by multiple threads.

In particular, it must satisfy the need for multiple threads to access the same shared data, and the need for a shared piece of data to be accessed by only one thread at any given time.

Thread Safety Level

1. Function Level example: Global function in C Runtime Library

2. Instance Level example: File handle in Win32 API

3. Transaction Level example: Atomic Transaction in Database

COM Client needs know

Thread ≡ People

A Short Guide to Mastering Thread-Safety http://www.thinkingparallel.com/2006/10/15/a-short-guide-to-mastering-thread-safety/

Page 6: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

COM Assumption about Thread Safety

COM Assumption about Threading Issues

A COM client can not know whether a COM server is thread safety. (including it’s threading model)

Any COM client can access any COM server in anytime anywhere.

In design principle, threading issues is server’s problem not client.

COM Assumption: All COM Server must be thread safety

Synchronization on a per-call basis (Instance Level)

COM Client needs know

Page 7: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

COM Object (COM Server)

Apartment Model

Invoker Thread (COM Client)

Microsoft provides “Apartment Model” to reduce complexity of COM Thread Safety !?

Another reason is that COM (OLE1 1991) did not support Multithreading in Microsoft Windows 3.0 (only Cooperative or Non-preemptive multitasking), but it (COM, OLE2) supported that in Microsoft Windows NT 3.5 and Windows 95.

Apartment (Management Model)

Classify

Belong

Invoke

Page 8: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Apartment Models with Client Thread (1/2)What is Apartment? Apartment is a Property of a COM thread stored in Thread-Local Storage,

you can set/reset the property by COM API or Thread Class of .NET Framework.This attribute must be present on the entry point of any application that uses .NET Windows Forms, WPF or UI-oriented COM objects (ActiveX Control).

1. Single-threaded Apartment model (STA) [ 1 : 0 ~ n : 1 Process: STA : Thread]

available in Windows NT 3.51

2. Multi-threaded Apartment model (MTA) [ 1 : 0 ~ 1 : n Process: MTA : Thread] available in Windows NT 4.0 and Windows 95

3. Neutral Apartment (NA) [ 1 : 1 : 0 Process: NA : Thread] available in Windows 2000

COM Client needs know

To set apartment property is thread creator’s responsibility.

Page 9: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Apartment (Management Model)

Apartment Models with Client Thread (2/2)

STA 0 STA 1

MTA

NA

Window Message Pumping

STA n

Process 1

Share one Apartment

COM Client needs know

Ap

artm

ent

Bo

un

dar

y

NA

Invoker Thread (COM Client)

STA ≡ RoomMTA ≡ Dorm

NA ≡ Tea Room

Classify

Room Room Room

Dorm Tea Room

Page 10: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

What is COM Threading Model? Threading Model is a Property of a COM Server

COM Implementer can choice one and only one threading model to implement COM Server in design-time. But, it can not be changed in runtime.

Implementer does not handle all threading issuesImplementer does not consider the

threading issues in COM Object and Module.1. Single Thread Model (Single supports STA 0)

Implementer does not consider the threading issues in COM Object only. The implementer must synchronize access to any global variables, DllGetClassObject and DllCanUnloadNow.

2. Apartment Thread Model (Apartment supports multi-STAs)

Implementer MUST handle all threading issues in COM Object and Module

3. Free Thread Model (Free supports MTA)

4. Both Model (Both supports multi-STAs and MTA)

5. Neutral Model (Neutral supports NA)

Threading Models with COM Server (1/4)

COM Client needs know

Module global variables

CreateAccess

Object

Process

Page 11: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Threading Models with COM Server (2/4)

COM Server ≡ Oven

COM Client needs know

COM Object (COM Server)

Apartment (Management Model)

Belong

STA 0 STA 1

MTANA

STA n

Process

Ap

artm

ent

Bo

un

dar

y

NA

Neutral Model

Free, Both Model

Single, Apartment, Both Model

Apartment,Both Model

Page 12: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Threading Models with COM Server (3/4)

Page 13: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Threading Models with COM Server (4/4)The threading model is a Property of COM Server, the information is only stored in resource of COM binary and described only in registry and manifest.

Registry

SxS Manifest for COM Server

HKEY_CLASSES_ROOT\CLSID\<Subkey>

COM Client needs know

Default is Single when ThreadingModel value not present

Page 14: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Threading Models and Apartment Models (1/4)

General guidelines for participating threads and objects

1. A COM thread is also associated with an apartment (STA or MTA). (a thread in which COM objects are created or COM method calls are made)

2. Each COM object is associated with one and only one apartment (STA, MTA, or NA, not thread).

3. Method calls which are made inside the same apartment are performed directly without any assistance from COM. The key-points: Threading safety of Single and Apartment model is based on this guidelines.

4. Method calls made across apartments are achieved via marshalling. Please refer “Mixed Model Development”

COM Client needs know

Page 15: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Threading Models and Apartment Models (2/4)

NA

the same apartments

STA 0STA 1

MTA

STA n

Process 1

NA

Single Apartment

Single ApartmentBoth

Neutral

Oven

Tea Room

RoomRoom

Dorm People

COM Client needs know

Room

COM Object (COM Server)

Invoker Thread (COM Client)

Apartment (Management Model) Invoke

Apartment Boundary

3. All calls to the COM object must be made on its thread (within its apartment).

Free Both

Page 16: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

COM Server Threading Models

Client Thread Apartment model

COM Server associated in

Single STA If thread is STA0, COM object will be created in STA0. If it is not … (Incompatible apartment)

MTA (Incompatible apartment)

Apartment STA Client STA

MTA (Incompatible apartment)

Free STA (Incompatible apartment)

MTA MTA

Both STA Client STA

MTA MTA

Neutral STA/MTA NA (Incompatible apartment)

COM Client needs know

Threading Models and Apartment Models (3/4)

What thing is happened when COM Server is created in incompatible apartment (Cross Apartment)?

4. Method calls made across apartments are achieved via marshalling

Page 17: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Threading Models and Apartment Models (4/4)

NA

cross apartments

STA 0STA 1

MTA

STA n

Process 1

NA

Single Apartment

Free Both

Single ApartmentBoth

Neutral

Oven

Tea Room

DormDorm

Room People

COM Client needs know

Dorm

Apartment Boundary

illegal

4. Method calls made across apartments are achieved via marshalling

What thing is happened when COM Server is accessed by incompatible thread (Cross Apartment)?

Page 18: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

2. Mixed Model Development

1. COM Threading Models

2. Mixed Model Development

3. COM Interface Marshalling and Unmarshlling

4. COM Client Case Studies

5. Inside Standard Marshalling

6. COM Server Side Case Studies

7. Conclusion

Page 19: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Method calls made across apartments are achieved via marshalling.

Why? Microsoft provides Marshalling technique to resolve two problems

1. Let Single and Apartment COM Server thread safety, the designer does not consider threading issue during implementation.

2. COM is designed to allow clients to communicate transparently with objects, regardless of where those objects are running. (EX: DirectShow Graph Edit opens running graph by DOT)

Mixed Model Development

Apartment Another Apartment

ChannelSerialize arguments

Unserialize arguments

Proxy

Stub

across apartments

Concept of Marshalling

Pass serialized arguments by valueexcept interface

COM Server ≡ Phone

COM Client needs know

Page 20: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Concept of Marshalling (1/3)

Problem 1: Serialize → 1 Consumer- N Producer: queue and loop

Let Single and Apartment COM Server thread safety in different apartment, Marshalling technique will serialize all method calls which are accessed by cross or owner threads.

Serialize → 1 Consumer- N Producer: queue and loop

Process 1

Other Apartment

STA

Proxy

Stub

QueueInvoker thread

thread which creates COM Server

Thread Safety Key-Point: Every object lives on a single thread. All calls to an object must be made on its thread (within its apartment). It is forbidden to call an object directly from another thread.

Microsoft reuses Message Loop and Hidden Window to process invocation from different apartment in STA. Pass serialized arguments by

value (basically) with Message Queue

Direct call by stack

push

Single Apartment

Ap

artm

en

t B

ou

nd

ary

DispatchMessage

Accesses are serialized

Page 21: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Concept of Marshalling (2/3)

Each apartment/thread with objects in it must have a message queue in order to handle calls from other processes and apartments within the same process. This means simply that the thread's work function must have a GetMessage/DispatchMessage loop. (Include .NET managed code, Win Form and WPF)

COM Client needs know

PS. You can monitor the message via Spy++.

Get arguments

Invoke COM Object

Page 22: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Concept of Marshalling (3/3)

Cross process → Client-Server: socket, listen thread and worker thread

Process 1 Process 2

Proxy

Stub

Listen thread

Worker thread

The thread is created by COM Runtime.

Invoker thread

Pass serialized arguments by value (basically) with LPC/IPC, RPC, Other…

Direct call by stack

DispatcherProcess or Machine Boundarydifferent memory address space

Apartment

Problem 2: Cross Boundary Key-Point: All arguments need be serialized to cross boundary.COM is designed to allow clients to communicate transparently with objects, regardless of where those objects are running.

Microsoft ORPC Runtime

Apartment

TCP UDP IPX SPX HTTP “Falcon”

Protocol Stack (Pluggable Transports)

Accesses are not serialized.

Cross process → Client-Server: socket, listen thread and worker thread

Page 23: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Ap

artm

en

t B

ou

nd

ary

Mixed Model Development of in-process Marshalling

Process

STA 1

STA 0ProxyStub

MTA

NA

Queue

Worker thread

DispatchMessage

Case 1

Invoker thread

thread which creates COM Server

COM Runtime

push

Free Both

Neutral

Single, Apartment Both

Stub

Stub

Dispatcher

Invoker thread

Pass serialized arguments by value (basically) with Shared memory, LPC/IPC, RPC, Other…

Direct call by stack

Create Thread

like Case 2Thread

Pool

Listen thread

Page 24: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

MTA

Mixed Model Development of out-process Marshalling

Process 1

?A

Process 2

ProxyDispatcher

Worker thread

Case 2Pass serialized arguments by value (basically) with Shared memory, LPC/IPC, RPC, Other…

Direct call by stack

STA 0Stub

Queue

thread which creates COM Server

NA

push

Neutral

Free Both

COM Runtime

Stub

StubInvoker thread

Create Thread

Pro

cess

or

Mac

hin

e B

ou

nd

ary

Single ApartmentBoth

Worker thread

DispatchMessage

Ap

artm

en

t B

ou

nd

ary

like Case 2

Case 1

ThreadPool

Listen thread

Worker thread

Page 25: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Creating COM Server in Mixed-Apartment case

COM Server Threading Models

Client Thread Apartment model

Get COM Object pointer from CoCreateInstance

COM Server associated in

Single STA If(thread is STA0) direct pointerelse proxy pointer

If thread is STA0, COM object will be created in STA0. If it is not, COM Runtime will create a STA0 thread (with a message pumping) to create and service the COM object (Cross apartment).

MTA proxy pointer If STA0 exists, COM object will be created in STA0. If it is not, COM Runtime will create a STA0 thread (with a message pumping) to create and service the COM object (Cross apartment).

Apartment STA direct pointer Client STA (Wish the thread has a message pumping)

MTA proxy pointer COM Runtime will create a STA thread (with a message pumping) to create and service the COM object (Cross apartment).

Free STA proxy pointer COM Runtime will create a MTA thread in thread pool (without a message pumping) to create the COM object (Cross apartment).

MTA direct pointer MTA

Both STA direct pointer Client STA (Wish the thread has a message pumping)

MTA direct pointer MTA

Neutral STA/MTA proxy pointer NA (Cross apartment)

COM Client needs know

COM Runtime will handle all incompatible case Automatically.

Page 26: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Accessing COM Server in Mixed-Apartment case

NA

cross apartments

STA 0STA 1

MTA

STA n

Process 1

NA

Single Apartment

Free Both

Single ApartmentBoth

Neutral

Oven

Tea Room

DormDorm

Room People

COM Client needs know

Dorm

Apartment Boundary

Apartment Another Apartment

ChannelSerialize arguments

Unserialize arguments

Proxy Stub

across apartments

Concept of Marshalling

How can I create Proxy and Stub of COM server Manually ?

Page 27: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

3. COM Interface Marshalling and Unmarshlling

1. COM Threading Models

2. Mixed Model Development

3. COM Interface Marshalling and Unmarshlling

4. COM Client Case Studies

5. Inside Standard Marshalling

6. COM Server Side Case Studies

7. Conclusion

Page 28: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

General guidelines

1. Proxy and Stub of COM Server are created by Interface Marshalling / Unmarshlling procedures.

2. The Interface Marshalling / Unmarshlling procedures can be Automatic in some case or Manual by COM client.

3. The Interface Unmarshlling procedure will decide the returned interface pointer is direct pointer or proxy pointer by apartment context.

4. To create Proxy and Stub of COM Server manually is Client’s responsibility when a thread accesses a COM Server which is associated different Apartment with caller thread.

In .NET managed code, the RCW will handle that automatically, but the proxy and stub will NOT be created automatically in native codes (C/C++).

Interoperability: How to create Proxy of COM Server

COM Client needs know

Page 29: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

1. Auto Marshalling: COM Runtime and Proxy will handle that.

A. CoCreateInstance, CoCreateInstanceEx, CoGetClassObject, Dynamic Creation

CoGetInstanceFromFile , and CoGetInstanceFromIStorage, will return a proxy when client thread is in incompatible apartment.

Auto Marshalling (1/2)

COM Client needs know

COM Server Threading Models

Client Thread Apartment model

Get COM Object pointer COM Server associated in

Single STA 1 ~ n proxy pointer COM Runtime will create a STA0 thread (with a message pumping) to create and service the COM object (Cross apartment).

MTA proxy pointer COM Runtime will create a STA0 thread (with a message pumping) to create and service the COM object (Cross apartment).

Apartment MTA proxy pointer COM Runtime will create a STA thread (with a message pumping) to create and service the COM object (Cross apartment).

Free STA proxy pointer COM Runtime will create a MTA thread (without a message pumping) to create the COM object (Cross apartment).

Neutral STA/MTA proxy pointer NA (Cross apartment)

Page 30: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

1. Auto Marshalling: COM Runtime and Proxy will handle that.

B. Any direct pointer pass in/return from a function by proxy, the direct pointer will be auto marshaled by proxy or direct pointer according to apartment context.

Auto Marshalling (2/2)

COM Client needs know

ApartmentAnother Apartment

Channel

y

Serialize arguments Unserialize arguments

Proxy of yStub of y

across apartments

Concept of Marshalling

xProxy of x

Stub of x

x->xxx()

y->Function1(x)

Imp. Function1

Direct call by stack

Page 31: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

2. Manual Marshalling: COM Runtime provides several methods to create proxy via marshalling an interface, these method can return proxy or direct pointer of COM object according to apartment context automatically.

1. Low Level: For all in-process, out-of-process, and cross-machine case: CoMarshalInterface, CoUnmarshalInterface

2. High Level: For in-process case: CoMarshalInterThreadInterfaceInStream, CoGetInterfaceAndReleaseStream

3. Optimization: For optimization for in-process:IGlobalInterfaceTable CLSID_StdGlobalInterfaceTable

Manual Marshalling (1/3)

COM Client needs know

The .NET RCW will handle in-process case automatically.

Page 32: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Manual Marshalling (2/3)

STA 1

Invoker thread

STA 0

Stub

Message Queue

push

Apartment Both

DispatchMessage

Marshal

Unmarshal

Proxy

Process

Pass serialized arguments by value (basically) with Shared memory, LPC/IPC, RPC, Other…

stream

Direct call by stack

Manual Marshalling 1 – Can handle all scenario

Apartment BoundaryInvoker thread

Owner thread

Get Proxy

Create Stub

COM Client needs know

Page 33: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Manual Marshalling (3/3)

Manual Marshalling 2 – Can marshal interface in-process only

Invoker thread

Owner thread

Get Proxy

Create Stub

COM Client needs know

Page 34: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

4. COM Client Case Studies

1. COM Threading Models

2. Mixed Model Development

3. COM Interface Marshalling and Unmarshlling

4. COM Client Case Studies

5. Inside Standard Marshalling

6. COM Server Side Case Studies

7. Conclusion

Must have Message Loop when STA thread shares COM object Must Interface Marshalling when cross thread accessing

Page 35: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Process

Nightmare of Marshalling - Episode 1-1

① An Apartment COM Server is created in STA thread 0. (will get direct pointer)

② The STA thread 0 passes the direct pointer to a STA/MTA thread 1 without Manual Marshalling. (The behavior is not according with COM convention)

③ The STA thread 1 calls the function of COM object via direct pointer, it is not thread safety, but it is callable (you will never get error code in this scenario), Horrible !!

Nightmare of Marshalling (1/8)

STA 1/ MTASTA 0

Unsafe

COM Client needs know

Single ApartmentBoth

The proxy and stub will NOT be created automatically

Page 36: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Nightmare of Marshalling - Episode 1-2

Nightmare of Marshalling (2/8)

COM Client needs know

STAMTA

Channel

y

Serialize arguments Unserialize arguments

Proxy of y Stub of yacross apartments

xChannel

Proxy of x

Stub of x

STAMTA

y

Proxy

xUnsafe

across apartments

Hold pointer

Hold pointer

Page 37: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Nightmare of Marshalling - Episode 2

① An Free COM Server is created in STA thread 0. (will get proxy)

② The STA thread 0 passes the pointer to a STA thread 1 without Manual Marshalling. (The behavior is not according with COM convention)

③ The STA thread 1 will get error code RPC_E_WRONG_THREAD when it calls the function of COM object via proxy. Thanks GOD, the bug is easy to find, but it is difficult to fix !!

You will get assess violation when threading model of COM object is Neutral.

Key-Point: The proxy is associated with one apartment only.

Process

Nightmare of Marshalling (3/8)

STA 0STA 1 MTA Proxy

Stub

RPC_E_WRONG_THREAD

COM Client needs know

Page 38: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Do we need Marshalling in PURE C++ environment !?Without/With interfaceMarshalling TS = Thread Safty ML = Message Loop ORPC = object remote procedure call

OwnerThread

InvokerThread

Single COM Apartment COM Both COMBoth COM with

FreeThreadedMarshaler

Free COM Neutral COM

Thread Safety technique Marshalling

argument by MLMarshalling

argument by MLCOM server itself* COM server itself* COM server itself

COM server itself

STA 0 Other STA

Work, not TS Episode 1-1

Work, not TS Episode 1-1

Work, but … Episode 1-2

Work*

Created in MTA/ NG PC_E_WRONG_THREA

DEpisode 2

NG*Episode 2

Created in STA 0/ Marshalling with

ML

Marshalling with ML

Marshalling with ML

Direct*Created in MTA

/ Marshalling with ORPC

Direct*

STA 1 ~ n

Other STA

Created in STA 0/ NG

PC_E_WRONG_THREAD

Episode 2

Work, not TS Episode 1-1

Work , but … Episode 1-2

Work*

Created in MTA/ NG PC_E_WRONG_THREA

DEpisode 2

NG*Episode 2

Created in STA 0/ Marshalling with

ML

Marshalling with ML

Episode 1

Marshalling with ML

Direct*Created in MTA

/ Marshalling with ORPC

Direct*

MTA

Created in STA 0/ NG

PC_E_WRONG_THREAD

Episode 2

Work, not TS Episode 1-1

Work , but … Episode 1-2

Work*

Created in MTA/ NG PC_E_WRONG_THREA

DEpisode 2

NG*Episode 2

Created in STA 0/ Marshalling with

ML

Marshalling with ML

Marshalling with ML

Direct*Created in MTA

/ Marshalling with ORPC

Direct*

MTA

STA

Created in STA 0/ NG

PC_E_WRONG_THREAD

Episode 2

Created in STA/ NG

PC_E_WRONG_THREAD

Episode 2

Work , but … Episode 1-2

Work*

Created in MTA/ NG PC_E_WRONG_THREA

DEpisode 2

NG*Episode 2

Created in STA 0/ Marshalling with

ML

Marshalling with ML

Marshalling with ORPC

Direct*Created in MTA

/ Marshalling with ORPC

Direct*

MTA

Created in STA 0/ NG

PC_E_WRONG_THREAD

Episode 2

Created in STA/ NG

PC_E_WRONG_THREAD

Episode 2

Work* Work* Work*NG*

Episode 2

Created in STA 0/ Marshalling with

ML

Marshalling with ML

Direct Direct* Direct Direct*

To out of process or remote process

NG NG NG NG NG NGMarshalling with

ORPCMarshalling with

ORPCMarshalling with

ORPCMarshalling with

ORPCMarshalling with

ORPCMarshalling with ORPC

COM Client needs know

Page 39: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Process

Nightmare of Marshalling - Episode 3① An Apartment COM Server is created in STA thread 0 but the thread without

message loop. (The behavior is not according with COM convention)

② The STA thread 0 passes the COM object to a STA/MTA thread 1 with Manual Marshalling.

③ The STA/MTA thread 1 calls the function of COM object via proxy. Block , Block, Block !!

Nightmare of Marshalling (4/8)

STA 0STA 1/MTA

Proxy

Stub

?

Block

COM Client needs know

Single ApartmentBoth

Page 40: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Nightmare of Marshalling - Episode 4 All behaviors are according with COM convention

① An Apartment COM Server is created in STA thread 0 and, the thread is UI thread (it has message loop).

② Purpose: The invocation does not block thread 0 to refresh UI.The STA thread 0 passes the COM object to a STA/MTA worker thread 1 with Manual Marshalling.

③ The STA/MTA thread 1 calls the function of COM object via proxy, but stub will call STA thread 0 to serve the invocation. thread 0 is busy, it can not refresh UI !!

It maybe is COM server’s problem. Please refer “Choosing the Threading Model”

Nightmare of Marshalling (5/8)

UI STA 0STA 1/MTA

StubProxy1

23

4

Process

Busy

COM Client needs know

Single ApartmentBoth

Page 41: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Nightmare of Marshalling (6/8)STA 0STA 1/MTA

Proxy

Stub

?

WAIT

WAIT

Nightmare of Marshalling - Episode 5

Deadlock !!

Process

Deadlock

COM Client needs know

Page 42: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Nightmare of Marshalling (7/8)STA 0STA 1/MTA

Proxy

StubWAIT and Check

WAIT

Solution of Episode 5Replace WaitForSingleObject to Wait WaitWithMessageLoop

Process

Deadlock-free!!

COM Client needs know

Page 43: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Process

Nightmare of Marshalling - Episode 6

Marshalling Interface mechanism is based on Apartment property of current thread (from TLS) and proxy (not COM object) to decide whether the Apartment context is compatible.

The meaning is that you can let Marshalling Interface mechanism confound with following scenario.

① An Apartment COM Server is created in STA thread 0. (will get direct pointer)

② The STA thread 0 passes the direct pointer to a STA thread 1 without Manual Marshalling. (The behavior is not according with COM convention)

③ The STA thread 1 passes the COM object to a STA/MTA thread 2 with Manual Marshalling. (The Marshalling Interface mechanism will decide the owner of COM object

is STA thread 1 but it is wrong, the correct is thread 0, Kidding !!)

In .NET Framework, the RCW (runtime-callable wrapper) will handle to create the proxy automatically, but if your code is mix native and managed code such as PInvoke to pass COM Interface and C++/CLI, the all native code must follow COM convention to pass a proxy interface cross apartment, otherwise …

Nightmare of Marshalling (8/8)STA 0STA2 / MTA STA 1

Proxy

Stub

To be continued

Unsafe , Kidding

COM Client needs know

Page 44: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

You can create many nightmares if COM Client or Server does not follow COM Marshalling Convention.

Nightmare of Marshalling

Nightmare To Be Continued !!

Caution !!

Page 45: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

5. Inside Standard Marshalling

1. COM Threading Models

2. Mixed Model Development

3. COM Interface Marshalling and Unmarshlling

4. COM Client Case Studies

5. Inside Standard Marshalling

6. COM Server Side Case Studies

7. Conclusion

Page 46: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Other Apartment

Inside Standard Marshalling (1/5)

COM Object

IUnknown

Pass serialized arguments by value (basically) with Shared memory, LPC/IPC, RPC, Other…

Arguments pass by stack

Invoke

ORPC Channel

IRpcChannelBuffer

ITest

Connect

ORPCChannel

IRpcChannelBuffer

Object ProxyManager

IUnknown

SendReceive GetBuffer

IUnknown

Object StubManager

ORPC

Ap

artm

en

t

Bo

un

dar

y

Apartment

IRpcProxyBuffer

Interface ITest Proxy

Marshallingarguments

ITestInterface ITest Stub

IRpcStubBuffer

Unmarshallingarguments

Apartment Another Apartment

ChannelSerialize arguments

Unserialize arguments

Proxy Stub

across apartments

Concept of Marshalling

Marshalling has two key-components

Page 47: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Inside Standard Marshalling (2/5)Marshalling has two key-components

1) Object Proxy Manager and Stub Manager (Object level)The Object Proxy and Stub are associated with COM object, it provide life control and channel management between two apartments.

StandardMarshaler

IMarshal

Object ProxyManager

Object StubManager

ORPCChannel

Create Create

Connect

■ Standard Marshaler (OLE32.DLL provided by Microsoft)

■ Custom Marshaler (COM server implements IMarshal Interface and handles all Marshalling issues)

■ Marshaler creates Object Proxy Manager and Stub Manager during Interface Marshalling and Unmarshalling procedures (CoMarshalInterface, CoUnmarshalInterface …)

■ Object Proxy Manager and Stub Manager create and connect RPC Channel (IRpcProxyBuffer IRpcStubBuffer, and IRpcChannelBuffer) between proxy and stub

Page 48: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

■ If the Interface is provided by Microsoft, the interface Proxy and Stub is implemented in OLE32.DLL and Microsoft’s DLL.

■ If COM Server is OLE Automation interface (has property oleautimation in interface of IDL) and it accords with Automation protocol. The COM Server don’t need implement Interface Proxy and Stub, but register TLB is necessary to use Universal Marshaler.

■ If the interface is Custom Interface, the source code of Interface Proxy and Stub is generated by MIDL compiler. It can be merged to COM DLL or separated to Proxy DLL. Caution !! The Interface Proxy and Stub is necessary.

Inside Standard Marshalling (3/5)

Marshalling has two key-components

2) Interface Proxy and Stub (Interface level) The Interface Proxy and Stub are associated with Interface not COM object, it only focus on arguments marshalling, unmarshalling and reconstruct call stack in function of interface.

{00020424-0000-0000-C000-000000000046}

Interface Proxy

Interface Stub

Marshallingarguments

Unmarshallingarguments

across apartments

PSFactoryObject

IPSFactoryBuffer CreateCreate

Page 49: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Implemented by MIDL in Proxy.DLL

Implemented by OLE32.DLL

Inside Standard Marshalling (4/5)Marshalling has two key-components

COM Object

IUnknown

ORPC Channel

IRpcChannelBuffer

Object ProxyManager

IUnknown IUnknown

Object StubManager

StandardMarshaler

IMarshal

Interface Stub

IRpcStubBuffer

PSFactoryObject IPSFactoryBuffer

IRpcProxyBuffer

Interface Proxy

Interface X

Interface X

2) Interface Proxy and Stub

1) Object Proxy Manager and Stub Manager

Implemented by MIDL in COM.DLL

■The Proxy DLL must be registered in registry or manifest.

Page 50: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Implemented by MIDL in Proxy.DLL

Implemented by OLE32.DLL

Other Apartment

Inside Standard Marshalling (5/5)

COM Object

IUnknown

Pass serialized arguments by value (basically) with Shared memory, LPC/IPC, RPC, Other…

Arguments pass by stack

Invoke

ORPC Channel

IRpcChannelBuffer

Create and manage

COM Aggregate*

ITest

Connect

ORPCChannel

IRpcChannelBuffer

Create and manage

Object ProxyManager

IUnknown

SendReceive GetBuffer

IUnknown

Object StubManager

ORPC

Proxy Stub

Ap

artm

en

t

Bo

un

dar

y

Apartment

PSFactoryObject

IPSFactoryBuffer

Life control

Interface and Life control

bind by IID bind by IID

IRpcProxyBuffer

Interface ITest Proxy

Marshallingarguments

StandardMarshaler

IMarshal

Create Create

CreateCreate

Relationship

ITest

connect

Interface ITest Stub

IRpcStubBuffer

Unmarshallingarguments

CoMarshalInterfaceCoUnmarshalInterface

stream

Page 51: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

How to bind Interface Proxy and Stub (1/2)

Interface Proxy and Stub Factory HKEY_CLASSES_ROOT\CLSID\<Subkey>

Interface Proxy and Stub relation info HKEY_CLASSES_ROOT\Interface\<Subkey>

PSFactoryObject IPSFactoryBuffer

1. From registry

Page 52: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

How to bind Interface Proxy and Stub (2/2)

SxS Manifest for Interface Proxy and Stub

PSFactoryObject IPSFactoryBuffer

2. From Manifest

Registration-Free Activation of COM Components: A Walkthroughhttp://msdn.microsoft.com/en-us/library/ms973913.aspx

Get CLSID via export functionGetProxyDllInfo.

Page 53: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

How to implement Interface Proxy and Stub (1/3)

The source code of Interface Proxy and Stub is generated by MIDL Compiler.

What is Microsoft Interface Definition Language?

MIDL defines interfaces between client and server programs in interface definition language (IDL) files required for remote procedure call (RPC) interfaces and COM/DCOM interfaces.

1. To define programming language independent Interface (IDL file)

2. To generate programming language dependent definition (C/C++: Header file)

3. To generate Interface Metadata (Type Library, TLB file)

4. To generate source code of Interface Proxy and Stub

MIDL is key-point to generate correct interface proxy and stub.

Page 54: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

How to implement Interface Proxy and Stub (2/3)

Separate and Merge Proxy and Stub to COM Server binary

Project.idl

Project.h

Project.tlb

Project.lib

Project_p.c

Project_i.c

Dlldata.c

Dlldatax.c

Generated Files

MIDL CompilerMidl.exe

Project Files

include

include

Implement of interface Proxy and Stub

Metadata of COM Server

Interface definitions in C/C++

CLSID/IIDdefinitions

The proxy/stub file, which includes the surrogate entry points both for clients and for servers.

Contains the data you need to create a proxy/stub DLL.

C/C++ Compiler and Linker

Others

Project.DLL

ProjectPS: If proxy is separated

COM Server binary

ProjectPS.DLLInterface Proxy and Stub

Link in RC

Implement PSFactoryObject

C/C++ Compiler and Linker

If proxy is merged

Page 55: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Merge Proxy and Stub to COM Server binaryDlldatax.c

Project.cpp

In merge proxy case, the proxy will be registered during COM registering.

In separate proxy case, the projectPS.DLL or other proxy DLL which implements the same interface MUST be registered, otherwise the CoMarshalInterXXX function and auto marshalling will not work and return error code E_NOINTERFACE.

How to implement Interface Proxy and Stub (3/3)

Page 56: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

IDL Interface Design Rules (1/2)

Interface

■ A interface must have a unique interface identifier (IID). IID of Interface Proxy and Stub conflict problem

■ A interface must be immutable. Once they are created and published, no part of their definition may change. Interface Proxy and Stub conflict problem

■ The current implementation of MIDL does not handle function overloading or multiple inheritance.

Page 57: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

IDL Interface Design Rules (2/2)

Function■ All interface methods must return an HRESULT

so that the portions of the system that handle remote processing can report RPC errors.

■ Your data types must be remotable

If you cannot convert a data type to a remotable type, you will have to create your own marshaling and unmarshaling routines. Also, LPVOID, or void *, has no meaning on a remote machine. Use a pointer to IUnknown, if necessary.

■ Key-points: Portable Type (ex: HWND, HANDLE, LPVOID… are not

acceptable) Non-reference value (except interface) Well define-size (except interface)

■ All string parameters in interface methods must be Unicode.

Page 58: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

FreeThreaded Marshaler

That way the client receives a real live pointer to the object. The client talks to the object directly without having to go through proxies and stubs in in-process case.

Great care should be exercised in using the CoCreateFreeThreadedMarshaler function. This is because the performance of objects which aggregate the free-threaded marshaler is obtained through a calculated violation of the rules of COM, with the ever-present risk of undefined behavior unless the object operates within certain restrictions. The most important restrictions are:

1. A free-threaded marshaler object cannot hold direct pointers to interfaces on an object that does not aggregate the free-threaded marshaler as part of its state. If the object were to use direct references to ordinary single-threaded aggregate objects, it may break their single threaded property. If the object were to use direct references to ordinary multi-threaded aggregate objects, these objects can behave in ways that show no sensitivity to the needs of direct single-threaded aggregate clients. For example, these objects can spin new threads and pass parameters to the threads that are references to ordinary single-threaded aggregate objects.

2. A free-threaded marshaler object cannot hold references to proxies to objects in other apartments. Proxies are sensitive to the threading model and can return RPC_E_WRONG_THREAD if called by the wrong client.

Page 59: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

6. COM Server Side Case Studies

1. COM Threading Models

2. Mixed Model Development

3. COM Interface Marshalling and Unmarshlling

4. COM Client Case Studies

5. Inside Standard Marshalling

6. COM Server Side Case Studies

7. Conclusion

Must implement and register Interface Proxy and StubMust understand Semantic of IDL and define correct Interface

Page 60: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Nightmare of Marshalling (1/6)

Nightmare of Marshalling – Episode 71. Forget to register Interface Proxy, Stub and Typelib in registry or

manifest.

You will get error code from CoCreateInstance, CoMarshalInterface and CoMarshalInterThreadInterfaceInStream

REGDB_E_IIDNOTREG (0x80040155) “Interface not registered”

E_NOINTERFACE (0x80004002) “No such interface supported”E_INVALIDARG (0x80070057) “One or more arguments are invalid” (Neutral COM Server Case)

TYPE_E_LIBNOTREGISTERED (0x80070057) “The type library is not registered” (Universal Marshaler Case)

2. Register incorrect or incompatible Interface Proxy and Stub in registry or manifest.

You will get crash in rpcrt4.dll, ole32.dll or ntdll.dll… or get invalid argument during function call or function return.

To registry COM Server will write default value in ProxySubClsid32 (Universal Marshaler). BUT the

Universal Marshaler CAN NOT work with custom interface usually.

{00020424-0000-0000-C000-000000000046}

Page 61: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Nightmare of Marshalling (2/6)

Nightmare of Marshalling - Episode 8

■ Use pointers to data very carefully. To re-create the data in the address space of the process that is called, the RPC run time must know the exact size of the data. Please use size_is, length_is, and max_is to specify size.

If, for example, a CHAR * parameter points to a buffer of characters rather than to a single character, the data cannot be correctly re-created. Use the syntax available with MIDL to accurately describe the data structures represented by your type definitions.

■ You will get crash in rpcrt4.dll, ole32.dll or ntdll.dll… or get invalid argument during function call or function return.

Page 62: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Nightmare of Marshalling (3/6)

Nightmare of Marshalling – Episode 9

Will not Marshal interface automatically

■ Use pointers to Interface very carefully.

To create the COM Proxy and Stub in the address space of the process that is called (Interface Marshalling), the RPC run time must know the interface type of the interface pointer. Please use iid_is, to specify IID.

You will get interface pointer without proxy and stub but the proxy and stub is necessary. Please recall Nightmare of Marshalling – Episode 1-2.

Page 63: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Nightmare of Marshalling (4/6)

Nightmare of Marshalling - Episode 10 (1/3)

What is the value result? 1, 2 or ???

COM Interface

COM Client PS. The pTest is proxy pointer.

COM Server

Aliasing

Pointer Attribute

unique ptr

pPtr1 and pPtr2

To point different address, the two values are 0.

To point the same address, the value is 0.

p1

p2

m1

p1

p2

m2

m3

p1

p2

m2

unique

ptr

Page 64: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Nightmare of Marshalling (5/6)

Nightmare of Marshalling - Episode 10 (2/3)

■ Be careful when argument is pointer and one of the following conditions is established. You DO NOT understand what meaning of the pointer attribute.

You can use ref, unique, and ptr to specify pointer argument and struct. Allocate/Relocate memory in COM Server, and pass it to client. Orphan client’s memory reference in COM Server. Aliasing memory reference.

■ The general rules for the manipulation of marshalled parameter data are simple:

1. The server can only allocate new memory or modify the memory specifically allocated by the server stub.

2. Reallocating or releasing existing memory for data can have a negative impact on the results and performance of the function call, and can be very difficult to debug.

Page 65: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Nightmare of Marshalling (6/6)

Characteristics\ Attribute of Pointer ref (default) unique ptr

Can have the NULL pointer. No Yes Yes

To describe the size of an array or union Yes No No

Can change the storage Yes[out, ref]

Yes[in, out, unique]

Yes [in, out, ptr]

Can change the pointer No Yes[in, out, unique]

Yes [in, out, ptr]

(NULL to non-NULL in COM Server)Can allocate new memory on the client.

n/a Yes[in, out, unique]

Yes [in, out, ptr]

(Non-NULL to NULL in COM Server) Can orphan memory on the client.

n/a Yes[in, out, unique]

Yes[in, out, ptr]

Can use existing memory on the client without allocating new memory.

n/a Yes[in, out, unique]

Yes[in, out, ptr]

(One non-NULL value to another in COM Server)

Can relocate new memory on the client.

Not recommend, because it is complex, server needs handle

n/a No Yes[in, out, ptr]

Aliasing (reconvergence and cycles reference) No No Yes

Overhead Low Middle High

Nightmare of Marshalling - Episode 10 (3/3)

Page 66: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

7. Conclusion 

1. COM Threading Models

2. Mixed Model Development

3. COM Interface Marshalling and Unmarshlling

4. COM Client Case Studies

5. Inside Standard Marshalling

6. COM Server Side Case Studies

7. Conclusion

Page 67: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Profiling of Proxy and Stub

Profiling Single, Apartment and Both COM Server

Free and Both COM Server

Neutral COM Server

The same Apartment

3 ms 3 ms N/A

Cross Apartment Message Loop

22,472 msWorker Thread

18,287 msThe same thread

1094 ms

100,0000 times function call, size of all argument is 44 bytes

Do noting

Page 68: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Choosing the COM Threading Model

Choosing the threading model for an object depends on the object's function.

■ Complexity of Implement (Single or Apartment) : Supporting the STA model is easier because COM runtime provides synchronization.

■ Maximum Response (Both, Free or Neutral) : MTA model is more difficult because the object must implement synchronization, but response to clients is better because synchronization is used for smaller sections of code, rather than for the whole interface call as provided by COM (Single and Apartment).

■ UI-Oriented (Single or Apartment) : This is necessary for UI-oriented COM objects, like controls and drag and drop, which must also be synchronized together with the UI.

■ Support Asynchronous Call (Both, Free or Neutral)

■ Overhead of Marshalling (Depend on context, Free)

Page 69: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

You can create many nightmares if COM Client or Server does not follow COM Marshalling Convention.

Caution !!

Conclusion

1. Must have Message Loop when STA thread shares COM object 2. Must Marshal Interface when cross thread accessing3. Must understand Semantic of IDL and define correct Interface4. Must implement and register Interface Proxy and Stub

Page 70: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Reference (1/5)

Reference-Counting Rules 1

Rule 1: AddRef must be called for every new copy of an interface pointer, and Release called for every destruction of an interface pointer, except where subsequent rules explicitly permit otherwise.

The following rules call out common nonexceptions to Rule 1.

•Rule 1a: In-out-parameters to functions. The caller must AddRef the actual parameter, since it will be Released by the callee when the out-value is stored on top of it. •Rule 1b: Fetching a global variable. The local copy of the interface pointer fetched from an existing copy of the pointer in a global variable must be independently reference counted, because called functions might destroy the copy in the global while the local copy is still alive. •Rule 1c: New pointers synthesized out of "thin air." A function that synthesizes an interface pointer using special internal knowledge, rather than obtaining it from some other source, must do an initial AddRef on the newly synthesized pointer. Important examples of such routines include instance creation routines, implementations of IUnknown::QueryInterface, and so on. •Rule 1d: Returning a copy of an internally stored pointer. After the pointer has been returned, the callee has no idea how its lifetime relates to that of the internally stored copy of the pointer. Thus, the callee must call AddRef on the pointer copy before returning it.

Page 71: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Reference (2/5)

Reference-Counting Rules 2

Rule 2: Special knowledge on the part of a piece of code of the relationships of the beginnings and the endings of the lifetimes of two or more copies of an interface pointer can allow AddRef/Release pairs to be omitted.

From a COM client's perspective, reference-counting is always a per-interface concept. Clients should never assume that an object uses the same reference count for all interfaces.

The return values of AddRef and Release should not be relied upon, and should be used only for debugging purposes.

Pointer stability; see details in the OLE Help file under "Reference-Counting Rules," subsection "Stabilizing the this Pointer and Keeping it Valid."

Page 72: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Reference (3/5)

Memory Management Rules 1

The lifetime management of pointers to interfaces is always accomplished through the AddRef and Release methods found on every COM interface. (See "Reference-Counting Rules" below.)

The following rules apply to parameters to interface member functions, including the return value, that are not passed "by-value":

• in parameters the caller should allocate and free the memory.

• out parameters must be allocated by the callee and freed by the caller using the standard COM memory allocator.

• in-out parameters are initially allocated by the caller, then freed and re-allocated by the callee if necessary. As with out parameters, the caller is responsible for freeing the final returned value. The standard COM memory allocator must be used.

Page 73: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Reference (4/5)

Memory Management Rules 2

Another area that needs special attention is the treatment of out and in-out parameters in failure conditions. If a function returns a failure code, the caller typically has no way to clean up the out or in-out parameters. This leads to the following additional rules:

1. In case of an error condition, parameters must always be reliably set to a value that will be cleaned up without any action by the caller.

2. All out pointer parameters must explicitly be set to NULL. These are usually passed in a pointer-to-pointer parameter but can also be passed as members of a structure that the caller allocates and the called code fills. The most straightforward way to ensure this is (in part) to set these values to NULL on function entry. This rule is important because it promotes more robust application interoperability.

3. Under error conditions, all in-out parameters must either be left alone by the code called (thus remaining at the value to which they were initialized by the caller) or be explicitly set, as in the out parameter error return case.

Remember that these memory management conventions for COM applications apply only across public interfaces and APIs—there is no requirement at all that memory allocation strictly internal to a COM application need be done using these mechanisms.

COM internally uses Remote Procedure Calls (RPC) to communicate between clients and servers. For more information about managing memory in RPC server stubs, see the Server-stub Memory Management topic.

Page 74: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Reference (5/5)

Memory Management Rules 3

■ The server should not attempt to reallocate or release [in] data, leaving the control of those spaces to the RPC server stub itself.

■ Generally, the server function implementation does not need to reallocate or release data marked with the [in, out] attribute. For fixed size data, the function implementation logic can directly modify the data.

■ If circumstances occur where the server routine has to reallocate the memory used by data marked with the [in, out] attribute, it is entirely possible that the server-side function implementation will not know if the pointer provided by the stub is to memory allocated with MIDL_user_allocate() or the marshaled wire buffer. To work around this problem, MS RPC can ensure that no memory leak or corruption occurs if the [force_allocate] attribute is set on the data. When [force_allocate] is set, the server stub will always allocate memory for the pointer, although the caveat is that performance will decrease for every use of it.

■ Pay attention to how you allocate and free memory. Remember that, unless you explicitly tell a COM object (by using the allocate attribute) not to free a data structure that was created during an out-of-process call, that structure will be destroyed when the call completes. Also, consider the potentially destructive overhead created by inefficient allocation of data structures that now need to be marshaled and unmarshaled.

Page 75: 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of Marshalling

Reference■Component Object Model (General) http://msdn2.microsoft.com/en-us/library/ms877981.aspx■Component Object Model, Part I http://graphcomp.com/info/specs/com/comch01.htm■Component Object Model, Part II http://graphcomp.com/info/specs/com/comch02.htm■Understanding and Using COM Threading Models (2004) http://msdn2.microsoft.com/en-us/library/ms809971.aspx■COM Macro Architecture Topology – Servers http://www.codeproject.com/KB/COM/macrotoposervers.aspx■COM IDs & Registry keys in a nutshell http://www.codeproject.com/KB/COM/mmtopo_comid.aspx■The COM Macro-Architecture Topology http://www.codeproject.com/KB/COM/macrotopomain.aspx

■Inside COM (1997)■Inter-Object Communication http://msdn.microsoft.com/en-us/library/ms693719(VS.85).aspx

■Essential COM (2000)■Standard Marshalling Architecture http://msdn.microsoft.com/en-us/library/ms810417.aspx■Descriptions and Workings of OLE Threading Models (2003) http://support.microsoft.com/kb/150777/en-us■OLE Threads Must Dispatch Messages (2005) http://support.microsoft.com/kb/136885/EN-US/■Understanding The COM Single-Threaded Apartment Part 1 (2005) http://69.10.233.10/KB/COM/CCOMThread.aspx■Understanding The COM Single-Threaded Apartment Part 2 (2005) http://69.10.233.10/KB/COM/CCOMThread2.aspx■Understanding Custom Marshalling Part 1 (2006) http://69.10.233.10/KB/COM/CustomMarshalling01.aspx

■Interface Marshalling http://msdn.microsoft.com/en-us/library/ms686605(VS.85).aspx■Choosing the Threading Model http://msdn2.microsoft.com/en-us/library/ms693779(VS.85).aspx■The Rules of the Component Object Model (1995) http://msdn2.microsoft.com/en-us/library/ms810016.aspx■Interface Design Rules http://msdn.microsoft.com/en-us/library/ms692709(VS.85).aspx

■Anatomy of an IDL File http://msdn.microsoft.com/en-us/library/ms690150(VS.85).aspx■MIDL Language Reference http://msdn2.microsoft.com/en-us/library/aa367088(VS.85).aspx■Remote Procedure Call (RPC) Programmer's Guide http://msdn.microsoft.com/en-us/library/aa374358(VS.85).aspx■Manifest Files Reference http://msdn.microsoft.com/en-us/library/aa375632(VS.85).aspx

■Mark Windows Forms entry points with STAThread http://msdn.microsoft.com/en-us/library/ms182351.aspx (Thanks Jim)■Registration-Free Activation of COM Components: A Walkthrough http://msdn.microsoft.com/en-us/library/ms973913.aspx■Registration-Free Activation of .NET-Based Components: A Walkthrough http://msdn.microsoft.com/en-us/library/ms973915.aspx