Ayende @ Rahien

Hi!
My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:

ayende@ayende.com

+972 52-548-6969

, @ Q c

Posts: 6,125 | Comments: 45,492

filter by tags archive

Unmanaged API “fun”, finding out MSMQ subqueues names in C#

time to read 26 min | 5169 words

I needed to get a list of subqueues of a queue, and there is no way of actually doing that in managed code. I decided that I can still use P/Invoke and just make the appropriate unmanaged calls. In hindsight, it would have been significantly simpler to just build an unmanaged DLL in C++/CLR, but I was already too deep, and I can never remember how to properly compile a C++ app anymore.

I finally had to slap myself a couple of times and remind me that I was a C++ developer for a long time, and I damn well should remember how to treat memory like it was something both sacred and abused. I had tested that on a Windows 2008 64 bits machine. During this project, I also found out that there is basically no information at all about this sort of thing, so I am putting the code here.

public class MsmqUtil
{
    internal const int PROPID_MGMT_QUEUE_SUBQUEUE_NAMES = 27;
    internal const ushort VT_NULL = 1;
 
    public static unsafe string[] GetMsmqSubQueueNames(string queueFormatName)
    {
        var props = new MQMGMTPROPS {cProp = 1};
        var variant = new MQPROPVariant {vt = VT_NULL};
        try
        {
            props.aPropID = Marshal.AllocHGlobal(sizeof (int));
            Marshal.WriteInt32(props.aPropID, PROPID_MGMT_QUEUE_SUBQUEUE_NAMES);
 
            props.aPropVar = Marshal.AllocHGlobal(Marshal.SizeOf(typeof (MQPROPVariant)));
            Marshal.StructureToPtr(new MQPROPVariant {vt = VT_NULL}, props.aPropVar, false);
 
            props.status = Marshal.AllocHGlobal(sizeof (int));
            Marshal.WriteInt32(props.status, 0);
 
            var result = MQMgmtGetInfo(null, "queue=" + queueFormatName, ref props);
            if (result != 0)
                throw new Win32Exception(result);
 
            if (Marshal.ReadInt32(props.status) != 0)
            {
                return null;
            }
 
            variant = (MQPROPVariant) Marshal.PtrToStructure(props.aPropVar, typeof (MQPROPVariant));
 
            var subQueues = new List<string>();
            for (int i = 0; i < variant.Val.calpwstr.cElems; i++)
            {
                var item = new string(variant.Val.calpwstr.pElems[i]);
                subQueues.Add(item);
            }
            return subQueues.ToArray();
        }
        finally
        {
            if (variant.vt != VT_NULL)
            {
                for (var i = 0; i < variant.Val.calpwstr.cElems; i++)
                {
                    MQFreeMemory(variant.Val.calpwstr.pElems[i]);
                }
                MQFreeMemory(variant.Val.calpwstr.pElems);
            }
            Marshal.FreeHGlobal(props.aPropID);
            Marshal.FreeHGlobal(props.aPropVar);
            Marshal.FreeHGlobal(props.status);
        }
    }
 
    [DllImport("mqrt.dll")]
    internal static extern int MQMgmtGetInfo([MarshalAs(UnmanagedType.BStr)] string computerName,
                                             [MarshalAs(UnmanagedType.BStr)] string objectName,
                                             ref MQMGMTPROPS mgmtProps);
 
    [DllImport("mqrt.dll")]
    internal static extern unsafe int MQFreeMemory(void* queue);
 
    [StructLayout(LayoutKind.Sequential)]
    internal struct CALPWSTR
    {
        public uint cElems;
        public unsafe char** pElems;
    }
 
    [StructLayout(LayoutKind.Sequential)]
    internal struct MQMGMTPROPS
    {
        public uint cProp;
        public IntPtr aPropID;
        public IntPtr aPropVar;
        public IntPtr status;
    }
 
    [StructLayout(LayoutKind.Sequential, Size = 16)]
    internal struct MQPROPVariant
    {
        public ushort vt;
        public ushort wReserved1;
        public ushort wReserved2;
        public ushort wReserved3;
        public UnionedVariant Val; //8
    }
 
    [StructLayout(LayoutKind.Explicit, Size = 8)]
    internal struct UnionedVariant
    {
        [FieldOffset(0)] public uint ulVal; /* VT_UI4    */
        [FieldOffset(0)] public CALPWSTR calpwstr; /* VT_VECTOR | VT_LPWSTR  */
    }
}

Comments

Drakiula

Thank you for sharing, too bad subqueues are not supported in MSMQ 3.0.

Comment preview

Comments have been closed on this topic.

FUTURE POSTS

  1. RavenDB 3.5 Whirlwind tour: I need to be free to explore my data - 13 hours from now
  2. RavenDB 3.5 whirl wind tour: I'll have the 3+1 goodies to go, please - 4 days from now
  3. The design of RavenDB 4.0: Voron has a one track mind - 5 days from now
  4. RavenDB 3.5 whirl wind tour: Digging deep into the internals - 6 days from now
  5. The design of RavenDB 4.0: Separation of indexes and documents - 7 days from now

And 11 more posts are pending...

There are posts all the way to May 30, 2016

RECENT SERIES

  1. The design of RavenDB 4.0 (14):
    05 May 2016 - Physically segregating collections
  2. RavenDB 3.5 whirl wind tour (14):
    04 May 2016 - I’ll find who is taking my I/O bandwidth and they SHALL pay
  3. Tasks for the new comer (2):
    15 Apr 2016 - Quartz.NET with RavenDB
  4. Code through the looking glass (5):
    18 Mar 2016 - And a linear search to rule them
  5. Find the bug (8):
    29 Feb 2016 - When you can't rely on your own identity
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats