From 02b501e4dc9a389878cd323e4f781bc752fec737 Mon Sep 17 00:00:00 2001 From: dolphin Date: Thu, 15 Aug 2013 09:32:12 -0700 Subject: Move the experience panel to the bottom of the editor floater --- indra/tools/vstool/DispatchUtility.cs | 271 ++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 indra/tools/vstool/DispatchUtility.cs (limited to 'indra/tools/vstool/DispatchUtility.cs') diff --git a/indra/tools/vstool/DispatchUtility.cs b/indra/tools/vstool/DispatchUtility.cs new file mode 100644 index 0000000000..6056ac55a1 --- /dev/null +++ b/indra/tools/vstool/DispatchUtility.cs @@ -0,0 +1,271 @@ +#region Using Directives + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.Reflection; +using System.Security.Permissions; + +#endregion + +namespace TestDispatchUtility +{ + /// + /// Provides helper methods for working with COM IDispatch objects that have a registered type library. + /// + public static class DispatchUtility + { + #region Private Constants + + private const int S_OK = 0; //From WinError.h + private const int LOCALE_SYSTEM_DEFAULT = 2 << 10; //From WinNT.h == 2048 == 0x800 + + #endregion + + #region Public Methods + + /// + /// Gets whether the specified object implements IDispatch. + /// + /// An object to check. + /// True if the object implements IDispatch. False otherwise. + public static bool ImplementsIDispatch(object obj) + { + bool result = obj is IDispatchInfo; + return result; + } + + /// + /// Gets a Type that can be used with reflection. + /// + /// An object that implements IDispatch. + /// Whether an exception should be thrown if a Type can't be obtained. + /// A .NET Type that can be used with reflection. + /// If doesn't implement IDispatch. + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + public static Type GetType(object obj, bool throwIfNotFound) + { + RequireReference(obj, "obj"); + Type result = GetType((IDispatchInfo)obj, throwIfNotFound); + return result; + } + + /// + /// Tries to get the DISPID for the requested member name. + /// + /// An object that implements IDispatch. + /// The name of a member to lookup. + /// If the method returns true, this holds the DISPID on output. + /// If the method returns false, this value should be ignored. + /// True if the member was found and resolved to a DISPID. False otherwise. + /// If doesn't implement IDispatch. + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + public static bool TryGetDispId(object obj, string name, out int dispId) + { + RequireReference(obj, "obj"); + bool result = TryGetDispId((IDispatchInfo)obj, name, out dispId); + return result; + } + + /// + /// Invokes a member by DISPID. + /// + /// An object that implements IDispatch. + /// The DISPID of a member. This can be obtained using + /// . + /// The arguments to pass to the member. + /// The member's return value. + /// + /// This can invoke a method or a property get accessor. + /// + public static object Invoke(object obj, int dispId, object[] args) + { + string memberName = "[DispId=" + dispId + "]"; + object result = Invoke(obj, memberName, args); + return result; + } + + /// + /// Invokes a member by name. + /// + /// An object. + /// The name of the member to invoke. + /// The arguments to pass to the member. + /// The member's return value. + /// + /// This can invoke a method or a property get accessor. + /// + public static object Invoke(object obj, string memberName, object[] args) + { + RequireReference(obj, "obj"); + Type type = obj.GetType(); + object result = type.InvokeMember(memberName, BindingFlags.InvokeMethod | BindingFlags.GetProperty, + null, obj, args, null); + return result; + } + + #endregion + + #region Private Methods + + /// + /// Requires that the value is non-null. + /// + /// The type of the value. + /// The value to check. + /// The name of the value. + private static void RequireReference(T value, string name) where T : class + { + if (value == null) + { + throw new ArgumentNullException(name); + } + } + + /// + /// Gets a Type that can be used with reflection. + /// + /// An object that implements IDispatch. + /// Whether an exception should be thrown if a Type can't be obtained. + /// A .NET Type that can be used with reflection. + private static Type GetType(IDispatchInfo dispatch, bool throwIfNotFound) + { + RequireReference(dispatch, "dispatch"); + + Type result = null; + int typeInfoCount; + int hr = dispatch.GetTypeInfoCount(out typeInfoCount); + if (hr == S_OK && typeInfoCount > 0) + { + // Type info isn't usually culture-aware for IDispatch, so we might as well pass + // the default locale instead of looking up the current thread's LCID each time + // (via CultureInfo.CurrentCulture.LCID). + dispatch.GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, out result); + } + + if (result == null && throwIfNotFound) + { + // If the GetTypeInfoCount called failed, throw an exception for that. + Marshal.ThrowExceptionForHR(hr); + + // Otherwise, throw the same exception that Type.GetType would throw. + throw new TypeLoadException(); + } + + return result; + } + + /// + /// Tries to get the DISPID for the requested member name. + /// + /// An object that implements IDispatch. + /// The name of a member to lookup. + /// If the method returns true, this holds the DISPID on output. + /// If the method returns false, this value should be ignored. + /// True if the member was found and resolved to a DISPID. False otherwise. + private static bool TryGetDispId(IDispatchInfo dispatch, string name, out int dispId) + { + RequireReference(dispatch, "dispatch"); + RequireReference(name, "name"); + + bool result = false; + + // Members names aren't usually culture-aware for IDispatch, so we might as well + // pass the default locale instead of looking up the current thread's LCID each time + // (via CultureInfo.CurrentCulture.LCID). + Guid iidNull = Guid.Empty; + int hr = dispatch.GetDispId(ref iidNull, ref name, 1, LOCALE_SYSTEM_DEFAULT, out dispId); + + const int DISP_E_UNKNOWNNAME = unchecked((int)0x80020006); //From WinError.h + const int DISPID_UNKNOWN = -1; //From OAIdl.idl + if (hr == S_OK) + { + result = true; + } + else if (hr == DISP_E_UNKNOWNNAME && dispId == DISPID_UNKNOWN) + { + // This is the only supported "error" case because it means IDispatch + // is saying it doesn't know the member we asked about. + result = false; + } + else + { + // The other documented result codes are all errors. + Marshal.ThrowExceptionForHR(hr); + } + + return result; + } + + #endregion + + #region Private Interfaces + + /// + /// A partial declaration of IDispatch used to lookup Type information and DISPIDs. + /// + /// + /// This interface only declares the first three methods of IDispatch. It omits the + /// fourth method (Invoke) because there are already plenty of ways to do dynamic + /// invocation in .NET. But the first three methods provide dynamic type metadata + /// discovery, which .NET doesn't provide normally if you have a System.__ComObject + /// RCW instead of a strongly-typed RCW. + /// + /// Note: The original declaration of IDispatch is in OAIdl.idl. + /// + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("00020400-0000-0000-C000-000000000046")] + private interface IDispatchInfo + { + /// + /// Gets the number of Types that the object provides (0 or 1). + /// + /// Returns 0 or 1 for the number of Types provided by . + /// + /// http://msdn.microsoft.com/en-us/library/da876d53-cb8a-465c-a43e-c0eb272e2a12(VS.85) + /// + [PreserveSig] + int GetTypeInfoCount(out int typeInfoCount); + + /// + /// Gets the Type information for an object if returned 1. + /// + /// Must be 0. + /// Typically, LOCALE_SYSTEM_DEFAULT (2048). + /// Returns the object's Type information. + /// + /// http://msdn.microsoft.com/en-us/library/cc1ec9aa-6c40-4e70-819c-a7c6dd6b8c99(VS.85) + /// + void GetTypeInfo(int typeInfoIndex, int lcid, [MarshalAs(UnmanagedType.CustomMarshaler, + MarshalTypeRef = typeof(System.Runtime.InteropServices.CustomMarshalers.TypeToTypeInfoMarshaler))] out Type typeInfo); + + /// + /// Gets the DISPID of the specified member name. + /// + /// Must be IID_NULL. Pass a copy of Guid.Empty. + /// The name of the member to look up. + /// Must be 1. + /// Typically, LOCALE_SYSTEM_DEFAULT (2048). + /// If a member with the requested + /// is found, this returns its DISPID and the method's return value is 0. + /// If the method returns a non-zero value, then this parameter's output value is + /// undefined. + /// Zero for success. Non-zero for failure. + /// + /// http://msdn.microsoft.com/en-us/library/6f6cf233-3481-436e-8d6a-51f93bf91619(VS.85) + /// + [PreserveSig] + int GetDispId(ref Guid riid, ref string name, int nameCount, int lcid, out int dispId); + + // NOTE: The real IDispatch also has an Invoke method next, but we don't need it. + // We can invoke methods using .NET's Type.InvokeMember method with the special + // [DISPID=n] syntax for member "names", or we can get a .NET Type using GetTypeInfo + // and invoke methods on that through reflection. + // Type.InvokeMember: http://msdn.microsoft.com/en-us/library/de3dhzwy.aspx + } + + #endregion + } +} -- cgit v1.2.3