Tidbits

Sharing COM objects between processes

A good 70% of this is taken more or less directly from the .NET Framework source code for the class IWbemClassObjectFreeThreaded and backed by an article from Raymond Chen.

With this code you can create a byte array based on a COM object with which you can create a reference to that COM object from a different process.


public static class ComMarshalHelper
{
    #region Externals
 
    [ResourceExposure(ResourceScope.None), DllImport("ole32.dll", PreserveSig = false)]
    private static extern void CoMarshalInterface([In] IStream pStm, [In] ref Guid riid, [In] IntPtr Unk, [In] uint dwDestContext, [In] IntPtr pvDestContext, [In] uint mshlflags);
 
    [ResourceExposure(ResourceScope.None), DllImport("ole32.dll", PreserveSig = false)]
    private static extern IntPtr CoUnmarshalInterface([In] IStream pStm, [In] ref Guid riid);
 
    [ResourceExposure(ResourceScope.None), DllImport("ole32.dll", PreserveSig = false)]
    private static extern IStream CreateStreamOnHGlobal(IntPtr hGlobalint fDeleteOnRelease);
 
    [ResourceExposure(ResourceScope.None), DllImport("ole32.dll", PreserveSig = false)]
    private static extern IntPtr GetHGlobalFromStream([In] IStream pstm);
 
    [ResourceExposure(ResourceScope.None), DllImport("kernel32.dll", PreserveSig = true)]
    private static extern IntPtr GlobalLock([In] IntPtr hGlobal);
 
    [ResourceExposure(ResourceScope.None), DllImport("kernel32.dll", PreserveSig = true)]
    private static extern int GlobalUnlock([In] IntPtr pData);
 
    private enum MSHCTX
    {
        MSHCTX_LOCAL = 0,
        MSHCTX_NOSHAREDMEM = 1,
        MSHCTX_DIFFERENTMACHINE = 2,
        MSHCTX_INPROC = 3
    }
 
    private enum MSHLFLAGS
    {
        MSHLFLAGS_NORMAL = 0,
        MSHLFLAGS_TABLESTRONG = 1,
        MSHLFLAGS_TABLEWEAK = 2,
        MSHLFLAGS_NOPING = 3
    }
 
    #endregion //Externals
 
    private static readonly Type CoClassAttributeType = typeof(CoClassAttribute);
 
    public static byte[] MarshalComObject<T>(T comObject)
    {
        Type type = typeof(T);
        Guid objectId = type.GUID;
        if (!type.IsInterface)
        {
            foreach (Type comInterface in type.GetInterfaces())
            {
                if (!comInterface.IsDefined(CoClassAttributeType))
                    continue;
 
                objectId = comInterface.GUID;
                break;
            }
        }
 
        IntPtr iUnknown = IntPtr.Zero;
        IStream? stream = null;
        IntPtr lockedStreamPointer = IntPtr.Zero;
        try
        {
            iUnknown = Marshal.GetIUnknownForObject(comObject);
            stream = CreateStreamOnHGlobal(IntPtr.Zero, 1);
            CoMarshalInterface(stream, ref objectId, iUnknown, (uint)MSHCTX.MSHCTX_LOCAL, IntPtr.Zero, (uint)MSHLFLAGS.MSHLFLAGS_NORMAL);
            stream.Stat(out STATSTG streamInfo, 0);
            byte[] array = new byte[streamInfo.cbSize];
            lockedStreamPointer = GlobalLock(GetHGlobalFromStream(stream));
            Marshal.Copy(lockedStreamPointer, array, 0, array.Length);
 
            return array;
        }
        finally
        {
            if (iUnknown != IntPtr.Zero)
                Marshal.Release(iUnknown);
 
            if (lockedStreamPointer != IntPtr.Zero)
                GlobalUnlock(lockedStreamPointer);
 
            if (stream is not null)
                Marshal.ReleaseComObject(stream);
        }
    }
 
    public static T UnmarshalComObject<T>(byte[] data)
    {
        Type type = typeof(T);
        Guid objectId = type.GUID;
        if (!type.IsInterface)
        {
            foreach (Type comInterface in type.GetInterfaces())
            {
                if (!comInterface.IsDefined(CoClassAttributeType))
                    continue;
 
                objectId = comInterface.GUID;
                break;
            }
        }
 
        IntPtr streamPointer = IntPtr.Zero;
        IStream? stream = null;
        try
        {
            streamPointer = Marshal.AllocHGlobal(data.Length);
            Marshal.Copy(data, 0, streamPointer, data.Length);
            stream = CreateStreamOnHGlobal(streamPointer, 0);
            IntPtr iUnknown = CoUnmarshalInterface(stream, ref objectId);
 
            return (T)Marshal.GetObjectForIUnknown(iUnknown);
        }
        finally
        {
            if (stream is not null)
                Marshal.ReleaseComObject(stream);
 
            if (streamPointer != IntPtr.Zero)
                Marshal.FreeHGlobal(streamPointer);
        }
    }
}

What’s the deal with the GetInterfaces?
We need the GUID of the interface, not the CoClass. This code simply tries to backtrack from the CoClass to the interface.

Why make MarshalComObject generic?
GetType won’t always give you what you expect. Often it will just be System.__ComObject, even if the variable you passed in was the actual type. The generic is simply to ensure we know which type the object belongs to for determining the correct GUID.


Here’s an example using the Microsoft XML COM library (v6.0):

Process A creates a document and fills it with data before it is marshaled.

DOMDocument60 document = new();
document.loadXML("<Root>Some text to fill out this string</Root>");
byte[] data = ComMarshalHelper.MarshalComObject(document);

Sharing data can happen any way you like. Since it isn’t very big, one method might be to just convert it into Base64 and pass it on as CLI argument.

Process B can now unmarshal it and output the XML content.

DOMDocument60 document = ComMarshalHelper.UnmarshalComObject<DOMDocument60>(data);
Console.WriteLine(document.xml);//Outputs '<Root>Some text to fill out this string</Root>'
Tidbits

My method for static methods on generic type parameters

Sorry to disappoint the people most likely to stumble upon this, I have no fancy method for providing real static methods in a generic context.
Short version:

  • Find the method through reflection
  • Compile into a Func
  • Store in generic base class

The idea is to call a method from a base class, which redirects the call to the intended method.


Let me give you an example right away, below it you’ll find the explanation:

public abstract class Parent<Twhere T : Parent<T>
{
    //Since this is a generic class, we'll have one Func for each T
    private static readonly Func<stringint> ChildGetCount;
 
    static Parent()
    {
        //Find the method
        Type[] types = { typeof(string) };
        MethodInfo methodInfo = typeof(T).GetMethod
        (
            nameof(GetCount), 
            BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly, 
            null, 
            types, 
            Array.Empty<ParameterModifier>()
        );
 
        //Verify the method exists and throw a dedicated exception if it doesn't (to make debugging easier)
        if (methodInfo is null)
            throw new MissingMethodException(typeof(T).FullName, nameof(GetCount));
 
        //Build an Expression to speed up performance
        ParameterExpression parameterExpression = Expression.Parameter(types[0]);
        MethodCallExpression methodCallExpression = Expression.Call(methodInfo, parameterExpression);
        Expression<Func<stringint>> expression = Expression.Lambda<Func<stringint>>
        (
            methodCallExpression, 
            parameterExpression
        );
 
        //Store the Func for later use
        ChildGetCount = expression.Compile();
    }
 
    public static int GetCount(string value) => ChildGetCount(value);
}
 
public class ChildA : Parent<ChildA>
{
    private new static int GetCount(string value) => value.Count(c => c == 'a');
}
 
public class ChildB : Parent<ChildB>
{
    private new static int GetCount(string value) => value.Count(c => c == 'b');
}
 
public class ChildC : Parent<ChildC>
{
    private new static int GetCount(string value) => value.Count(c => c == 'c');
}

One of the most important parts of this whole thing is the generic base class that is constrained to itself.
This way, due to the way generics work, we can force a unique parent class for each child type. And each of those parents will have the information about what exact type the child is.
By using reflection, we can now search for a specific method in that child type, and store a reference to it in the childs unique parent.
To improve performance I use System.Linq.Expression to compile the MethodInfo into a Func, but that’s not necessary to make all of this work.
Finally, we add a static method in the parent, which simply redirects the call to the stored Func.
Another unnecessary detail: I used the same name for the method in the parent and child classes.
This was mostly for cohesion, but needing the new keyword is also a good reminder that you have or haven’t “overridden” the required method yet.


With the code above we can now do this:

const string value = "a ab abc";
 
int countA = ChildA.GetCount(value);//3
int countB = ChildB.GetCount(value);//2
int countC = ChildC.GetCount(value);//1

Which we could have done with plain static methods too, of course. But we can also do this:

const string value = "a ab abc";
 
int genericCountA = Parent<ChildA>.GetCount(value);//3
int genericCountB = Parent<ChildB>.GetCount(value);//2
int genericCountC = Parent<ChildC>.GetCount(value);//1

Which finally allows for things like these, which were the whole reason I needed all of this in the first place:

public static int GenericGetCount<T>(string valuewhere T : Parent<T>
    => Parent<T>.GetCount(value);
const string value = "a ab abc";
 
int genericCountA = GenericGetCount<ChildA>(value);//3
int genericCountB = GenericGetCount<ChildB>(value);//2
int genericCountC = GenericGetCount<ChildC>(value);//1

Downsides to this approach:

First of all, this needs a very specific generic structure. Which can not always be done, mostly because you might already use generics for other reasons. At least not without some additional complications.

Secondly, the compiler doesn’t verify anything. You can add additional checks in the static initializer, and a simple test framework can verify if all children are working correctly. But it’s still noway near the level of compiler enforced security that you get with proper inheritance. It also requires more awareness on the side of the developer, making it less comfortable to work with.

Lastly, the performance impact isn’t something you should blindly ignore. Reflection is still relatively costly. And the generic base class means we have a lot of additional classes once compiled (one for each child). Nothing too disruptive, but certainly something to keep in mind.

Tidbits

Finally is no catch-all

This is just a short “nice to know” for C# exception handling, that i only learned about after half an hour of frustrated debugging.


Imagine some code which changes persistent data. Might be files, a database or some OS settings. Just something that stays even after your program closes.
Now imagine you have to change this data to make an important operation, but have to change it back after you’re done so you won’t mess up something else.

SetSystemValue();
DoWork();
ResetSystemValue();

What if something unexpected happens in DoWork?
The changes we made won’t be changed back. Can’t have that.
So, we do what we learned is the proper way of dealing with the unexpected:

try
{
    SetSystemValue();
    DoWork();
}
finally
{
    ResetSystemValue();
}

Now, no matter what happens in the try block, the changes we’ve made are going to be reversed.


Only, there is a condition to finally you usually don’t need to think about:
It isn’t executed until after catch.
And when there is no catch, the program just terminates.

See the problem?
Usually there will be a catch somewhere up the chain to handle the exception.
And if there isn’t and the program terminates, we don’t have to worry about some invalid data in our program anyway.

In this case however, the data exists outside the program, meaning any issues persist with it.


Solution:
Add a catch somewhere. Specifically a catch that doesn’t (re-)throw an exception. Having a try/catch at your programs root for logging might be useful anyway.
Of course, if you already have a try/finally, why not simply add a catch in there as well?
In my case I simply doubled down on the reset part (to avoid calling it twice), which now looks somewhat like this:

try
{
    SetSystemValue();
    DoWork();
}
catch
{
    ResetSystemValue();
    return;
}
 
ResetSystemValue();