-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Description
Background and Motivation
The ComWrappers API is intended to permit external developers the ability to create standalone COM interop platforms. During the shut down of the .NET 5 release it was determined the COM Aggregation scenarios are difficult to handle properly. There are two updates that would assist making the scenario less magic and clearer to describe and document.
Proposed API
Modification (1) - Add 2 new values - Aggregation to indicate aggregation and Unwrap to indicate the IntPtr should be inspected if it is a CCW first - to the CreateObjectFlags enumeration.
namespace System.Runtime.InteropServices
{
[System.FlagsAttribute]
public enum CreateObjectFlags
{
None = 0,
TrackerObject = 1,
UniqueInstance = 2,
+ Aggregation = 4,
+ Unwrap = 8,
}
}Modification (2) - Add a new API overload for ComWrappers.GetOrRegisterObjectForComInstance() that accepts an inner value. The details of what this inner value represents are found in the official COM Aggregation documentation.
namespace System.Runtime.InteropServices
{
public abstract class ComWrappers
{
public object GetOrRegisterObjectForComInstance(System.IntPtr externalComObject, CreateObjectFlags flags, object wrapper);
+ public object GetOrRegisterObjectForComInstance(System.IntPtr externalComObject, CreateObjectFlags flags, object wrapper, System.IntPtr inner);
}
}Usage Examples
The scenario in question is non-trivial and difficult to reduce to a comprehensible example - below is an annotated attempt.
// A globally accessible ComWrappers instance.
ComWrappers cw = ...;
object createdWrapper = ...;
// Create native outer based on createdWrapper.
IntPtr outer = ...;
// Create native instance and aggregate with the above outer.
// In the aggregation scenario it is required to request the IUnknown interface.
Guid clsid = typeof(Demo).GUID;
Guid IID_IUnknown = typeof(IUnknown).GUID;
IntPtr inner = Native.CoCreateInstance(ref clsid, ref IID_IUnknown, outer);
// Retrieve the default interface from the inner.
Guid iid = typeof(IDemo).GUID;
IntPtr defInterface;
Marshal.QueryInterface(inner, ref iid, out defInterface);
// Register the created wrapper for the supplied default interface.
cw.GetOrRegisterObjectForComInstance(defInterface, CreateObjectFlags.Aggregation, createdWrapper, inner);Alternative Designs
No alternative designs were considered.
Risks
There are few if any risks. This is simply a better surface area for a cumbersome and poorly describable scenario.