Wednesday, November 14, 2012

Ask what that COM object is

Man this is helpful, if you are working with any COM objects. Ask it what type it is - HowTo: get the actual type name behind System.__ComObject with Visual C# or VB.NET
    public class ComHelper 
    { 
        /// <summary> 
        /// Returns a string value representing the type name of the specified COM object. 
        /// </summary> 
        /// <param name="comObj">A COM object the type name of which to return.</param> 
        /// <returns>A string containing the type name.</returns> 
        public static string GetTypeName(object comObj) 
        { 
 
            if (comObj == null) 
                return String.Empty; 
 
            if (!Marshal.IsComObject(comObj)) 
                //The specified object is not a COM object 
                return String.Empty; 
 
            IDispatch dispatch = comObj as IDispatch; 
            if (dispatch == null) 
                //The specified COM object doesn't support getting type information 
                return String.Empty; 
 
            System.Runtime.InteropServices.ComTypes.ITypeInfo typeInfo = null; 
            try 
            { 
                try 
                { 
                    // obtain the ITypeInfo interface from the object 
                    dispatch.GetTypeInfo(0, 0, out typeInfo); 
                } 
                catch (Exception ex) 
                { 
                    #if LINQPAD
                    ex.Dump();
                    #endif
                    //Cannot get the ITypeInfo interface for the specified COM object 
                    return String.Empty; 
                } 
 
                string typeName = ""; 
                string documentation, helpFile; 
                int helpContext = -1; 
 
                try 
                { 
                    //retrieves the documentation string for the specified type description 
                    typeInfo.GetDocumentation(-1, out typeName, out documentation, 
                        out helpContext, out helpFile); 
                } 
                catch (Exception ex) 
                { 
                    // Cannot extract ITypeInfo information 
                    return String.Empty; 
                } 
                return typeName; 
            } 
            catch (Exception ex) 
            { 
                // Unexpected error 
                return String.Empty; 
            } 
            finally 
            { 
                if (typeInfo != null) Marshal.ReleaseComObject(typeInfo); 
            } 
        } 
    } 
 
    /// <summary> 
    /// Exposes objects, methods and properties to programming tools and other 
    /// applications that support Automation. 
    /// </summary> 
    [ComImport()] 
    [Guid("00020400-0000-0000-C000-000000000046")] 
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    interface IDispatch 
    { 
        [PreserveSig] 
        int GetTypeInfoCount(out int Count); 
 
        [PreserveSig] 
        int GetTypeInfo( 
            [MarshalAs(UnmanagedType.U4)] int iTInfo, 
            [MarshalAs(UnmanagedType.U4)] int lcid, 
            out System.Runtime.InteropServices.ComTypes.ITypeInfo typeInfo); 
 
        [PreserveSig] 
        int GetIDsOfNames( 
            ref Guid riid, 
            [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] 
            string[] rgsNames, 
            int cNames, 
            int lcid, 
            [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId); 
 
        [PreserveSig] 
        int Invoke( 
            int dispIdMember, 
            ref Guid riid, 
            uint lcid, 
            ushort wFlags, 
            ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, 
            out object pVarResult, 
            ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo, 
            IntPtr[] pArgErr); 
    }

Automate Visual Studio from Linqpad

I really love LinqPad. Not that it doesn't have features I want, but that it just handles so many things in a convienent way. Starting with the whopping 6mb size. Enough about that. I was just sure that there was a way to reach into Visual Studio from another process and do stuff. I had forgotten how. I had forgotten that I had even succeeded before. I tried to find a way again. This is the rather short magic that was needed.
var dte = (EnvDTE.DTE)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE");
and a simple ask/command sample in linqpad
    const string SolutionExplorerWindow="{3AE79031-E1BC-11D0-8F78-00A0C9110057}";
 const string SolutionFolder="{66A26720-8FB5-11D2-AA7E-00C04F688DDE}";
 //EnvDTE.DTE
 var dte = (EnvDTE.DTE)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE");
 dte.Dump();
 dte.FileName.Dump();
 dte.Solution.FullName.Dump();
 dte.Windows.Item(SolutionExplorerWindow).Activate();
 //var uih=dte.ActiveWindow.Object as UIHierarchy;

Url Rewrite UI lies!

Url rewrite lies in the setup UI =( Take this pattern `piwik/piwik.php*` using wildcard matching (not regex) click Test Pattern and enter input data to test `piwik/piwik.php?anything=match` it claims `{R:0}` will then include the query string for the action properties. It lies.
When I setup a diagnostic page to see what was coming across from the rewrite, there were no query string arguments, unless the Append query string box was checked. =(