2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of...
-
Upload
james-hsieh -
Category
Technology
-
view
3.262 -
download
1
Transcript of 2008 07 31 Understanding and Using COM Threading Model - An Inconvenient Truth and Nightmare of...
Understanding and Using
COM Threading Model
Recording Engine, DDR TeamJames S. Hsieh
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
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
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
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/
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
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
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.
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
…
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
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
…
Threading Models with COM Server (3/4)
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
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
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
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
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)?
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
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
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
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
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
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
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
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.
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 ?
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
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
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)
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
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.
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
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
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
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
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
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
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
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
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
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
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
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
You can create many nightmares if COM Client or Server does not follow COM Marshalling Convention.
Nightmare of Marshalling
Nightmare To Be Continued !!
Caution !!
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
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
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
■ 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
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.
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
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
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.
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.
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
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)
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.
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.
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.
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
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}
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.
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.
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
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.
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)
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
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
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)
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
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.
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."
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.
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.
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.
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