Esempio n. 1
0
        /// <summary>
        /// Use this static method to cast a wrapped proxy to a new wrapper proxy of the supplied type.
        /// In English, use this to cast you base "COM" interface to a specialized interface.
        /// E.G. Outlook Item -> MailItem
        /// </summary>
        /// <typeparam name="T">the type you want to cast to</typeparam>
        /// <param name="wrapperProxy">The wrapper interface, e.g. something you got back from calling GetItem</param>
        /// <returns>A new wrapper proxy for the specified type</returns>
        public static T Cast <T>(object wrapperProxy)
        {
            if (wrapperProxy == null)
            {
                return(default(T));
            }

            Type       newType    = typeof(T);
            COMWrapper oldWrapper = RemotingServices.GetRealProxy(wrapperProxy) as COMWrapper;

            if (oldWrapper == null)
            {
                throw new ArgumentException("wrapper proxy was no COMWrapper");
            }
            if (oldWrapper._InterceptType.IsAssignableFrom(newType))
            {
                COMWrapper newWrapper = new COMWrapper(oldWrapper._COMObject, newType, oldWrapper._TargetName);
                return((T)newWrapper.GetTransparentProxy());
            }
            throw new InvalidCastException(string.Format("{0} is not assignable from {1}", oldWrapper._InterceptType, newType));
        }
        /// <summary>
        /// Dump the Type-Information for the COM type to the log, this uses reflection
        /// </summary>
        /// <param name="wrapperProxy">wrapperProxy to inspect</param>
        public static void DumpTypeInfo(object wrapperProxy)
        {
            Type comType = COMWrapper.GetUnderlyingType(wrapperProxy);

            if (comType == null)
            {
                LOG.InfoFormat("Can't get Typeinformation");
                return;
            }
            LOG.InfoFormat("Type information for COM object with name: {0}", comType.Name);
            try {
                foreach (MemberInfo memberInfo in comType.GetMembers())
                {
                    LOG.InfoFormat("Member: {0};", memberInfo.ToString());
                }
            } catch (Exception memberException) {
                LOG.Error(memberException);
            }
            try {
                foreach (PropertyInfo propertyInfo in comType.GetProperties())
                {
                    LOG.InfoFormat("Property: {0};", propertyInfo.ToString());
                }
            } catch (Exception propertyException) {
                LOG.Error(propertyException);
            }
            try {
                foreach (FieldInfo fieldInfo in comType.GetFields())
                {
                    LOG.InfoFormat("Field: {0};", fieldInfo.ToString());
                }
            } catch (Exception fieldException) {
                LOG.Error(fieldException);
            }
            LOG.InfoFormat("Type information end.");
        }
Esempio n. 3
0
        /// <summary>
        /// Gets a COM object and returns the transparent proxy which intercepts all calls to the object
        /// </summary>
        /// <param name="type">Interface which defines the method and properties to intercept</param>
        /// <returns>Transparent proxy to the real proxy for the object</returns>
        /// <remarks>The <paramref name="type"/> must be an interface decorated with the <see cref="ComProgIdAttribute"/>attribute.</remarks>
        public static T GetInstance <T>()
        {
            Type type = typeof(T);

            if (null == type)
            {
                throw new ArgumentNullException("type");
            }
            if (!type.IsInterface)
            {
                throw new ArgumentException("The specified type must be an interface.", "type");
            }

            ComProgIdAttribute progIDAttribute = ComProgIdAttribute.GetAttribute(type);

            if (null == progIDAttribute || null == progIDAttribute.Value || 0 == progIDAttribute.Value.Length)
            {
                throw new ArgumentException("The specified type must define a ComProgId attribute.", "type");
            }
            string progId = progIDAttribute.Value;

            // Convert from clsid to Prog ID, if needed
            if (progId.StartsWith("clsid:"))
            {
                Guid guid   = new Guid(progId.Substring(6));
                int  result = ProgIDFromCLSID(ref guid, out progId);
                if (result != 0)
                {
                    //LOG.WarnFormat("Error {0} getting progId {1}", result, progIDAttribute.Value);
                }
                else
                {
                    //LOG.InfoFormat("Mapped {0} to progId {1}", progIDAttribute.Value, progId);
                }
            }

            object comObject = null;

            try {
                comObject = Marshal.GetActiveObject(progId);
            } catch (COMException comE) {
                if (comE.ErrorCode == MK_E_UNAVAILABLE)
                {
                    //LOG.DebugFormat("No current instance of {0} object available.", progId);
                }
                else if (comE.ErrorCode == CO_E_CLASSSTRING)
                {
                    //LOG.WarnFormat("Unknown progId {0}", progId);
                }
                else
                {
                    //LOG.Warn("Error getting active object for " + progId, comE);
                }
            } catch (Exception) {
                //LOG.Warn("Error getting active object for " + progId, e);
            }

            if (comObject != null)
            {
                COMWrapper wrapper = new COMWrapper(comObject, type);
                return((T)wrapper.GetTransparentProxy());
            }
            return(default(T));
        }
Esempio n. 4
0
        /// <summary>
        /// Intercept method calls
        /// </summary>
        /// <param name="myMessage">
        /// Contains information about the method being called
        /// </param>
        /// <returns>
        /// A <see cref="ReturnMessage"/>.
        /// </returns>
        public override IMessage Invoke(IMessage myMessage)
        {
            IMethodCallMessage callMessage = myMessage as IMethodCallMessage;

            if (null == callMessage)
            {
                //LOG.DebugFormat("Message type not implemented: {0}", myMessage.GetType().ToString());
                return(null);
            }

            MethodInfo method = callMessage.MethodBase as MethodInfo;

            if (null == method)
            {
                //LOG.DebugFormat("Unrecognized Invoke call: {0}", callMessage.MethodBase.ToString());
                return(null);
            }

            object returnValue = null;

            object[] outArgs      = null;
            int      outArgsCount = 0;

            string       methodName = method.Name;
            Type         returnType = method.ReturnType;
            BindingFlags flags      = BindingFlags.InvokeMethod;
            int          argCount   = callMessage.ArgCount;

            object invokeObject;
            Type   invokeType;
            Type   byValType;

            object[] args;
            object   arg;

            COMWrapper[] originalArgs;
            COMWrapper   wrapper;

            ParameterModifier[] argModifiers = null;
            ParameterInfo[]     parameters   = null;
            ParameterInfo       parameter;

            if ("Dispose" == methodName && 0 == argCount && typeof(void) == returnType)
            {
                this.Dispose();
            }
            else if ("ToString" == methodName && 0 == argCount && typeof(string) == returnType)
            {
                returnValue = this.ToString();
            }
            else if ("GetType" == methodName && 0 == argCount && typeof(System.Type) == returnType)
            {
                returnValue = this._InterceptType;
            }
            else if ("GetHashCode" == methodName && 0 == argCount && typeof(int) == returnType)
            {
                returnValue = this.GetHashCode();
            }
            else if ("Equals" == methodName && 1 == argCount && typeof(bool) == returnType)
            {
                returnValue = this.Equals(callMessage.Args[0]);
            }
            else if (1 == argCount && typeof(void) == returnType && (methodName.StartsWith("add_") || methodName.StartsWith("remove_")))
            {
                bool removeHandler = methodName.StartsWith("remove_");
                methodName = methodName.Substring(removeHandler ? 7 : 4);

                Delegate handler = callMessage.InArgs[0] as Delegate;
                if (null == handler)
                {
                    return(new ReturnMessage(new ArgumentNullException("handler"), callMessage));
                }
            }
            else
            {
                invokeObject = this._COMObject;
                invokeType   = this._COMType;

                if (methodName.StartsWith("get_"))
                {
                    // Property Get
                    methodName = methodName.Substring(4);
                    flags      = BindingFlags.GetProperty;
                    args       = callMessage.InArgs;
                }
                else if (methodName.StartsWith("set_"))
                {
                    // Property Set
                    methodName = methodName.Substring(4);
                    flags      = BindingFlags.SetProperty;
                    args       = callMessage.InArgs;
                }
                else
                {
                    args = callMessage.Args;
                    if (null != args && 0 != args.Length)
                    {
                        // Modifiers for ref / out parameters
                        argModifiers    = new ParameterModifier[1];
                        argModifiers[0] = new ParameterModifier(args.Length);

                        parameters = method.GetParameters();
                        for (int i = 0; i < parameters.Length; i++)
                        {
                            parameter = parameters[i];
                            if (parameter.IsOut || parameter.ParameterType.IsByRef)
                            {
                                argModifiers[0][i] = true;
                                outArgsCount++;
                            }
                        }

                        if (0 == outArgsCount)
                        {
                            argModifiers = null;
                        }
                    }
                }

                // Un-wrap wrapped COM objects before passing to the method
                if (null == args || 0 == args.Length)
                {
                    originalArgs = null;
                }
                else
                {
                    originalArgs = new COMWrapper[args.Length];
                    for (int i = 0; i < args.Length; i++)
                    {
                        if (null != args[i] && RemotingServices.IsTransparentProxy(args[i]))
                        {
                            wrapper = RemotingServices.GetRealProxy(args[i]) as COMWrapper;
                            if (null != wrapper)
                            {
                                originalArgs[i] = wrapper;
                                args[i]         = wrapper._COMObject;
                            }
                        }
                        else if (0 != outArgsCount && argModifiers[0][i])
                        {
                            byValType = GetByValType(parameters[i].ParameterType);
                            if (byValType.IsInterface)
                            {
                                // If we're passing a COM object by reference, and
                                // the parameter is null, we need to pass a
                                // DispatchWrapper to avoid a type mismatch exception.
                                if (null == args[i])
                                {
                                    args[i] = new DispatchWrapper(null);
                                }
                            }
                            else if (typeof(Decimal) == byValType)
                            {
                                // If we're passing a decimal value by reference,
                                // we need to pass a CurrencyWrapper to avoid a
                                // type mismatch exception.
                                // http://support.microsoft.com/?kbid=837378
                                args[i] = new CurrencyWrapper(args[i]);
                            }
                        }
                    }
                }

                try {
                    returnValue = invokeType.InvokeMember(methodName, flags, null, invokeObject, args, argModifiers, null, null);
                } catch (Exception ex) {
                    return(new ReturnMessage(ex, callMessage));
                }

                // Handle enum and interface return types
                if (null != returnValue)
                {
                    if (returnType.IsInterface)
                    {
                        // Wrap the returned value in an intercepting COM wrapper
                        if (Marshal.IsComObject(returnValue))
                        {
                            returnValue = COMWrapper.Wrap(returnValue, returnType);
                        }
                    }
                    else if (returnType.IsEnum)
                    {
                        // Convert to proper Enum type
                        returnValue = Enum.Parse(returnType, returnValue.ToString());
                    }
                }

                // Handle out args
                if (0 != outArgsCount)
                {
                    outArgs = new object[args.Length];
                    for (int i = 0; i < parameters.Length; i++)
                    {
                        if (!argModifiers[0][i])
                        {
                            continue;
                        }

                        arg = args[i];
                        if (null == arg)
                        {
                            continue;
                        }

                        parameter = parameters[i];
                        wrapper   = null;

                        byValType = GetByValType(parameter.ParameterType);
                        if (typeof(Decimal) == byValType)
                        {
                            if (arg is CurrencyWrapper)
                            {
                                arg = ((CurrencyWrapper)arg).WrappedObject;
                            }
                        }
                        else if (byValType.IsEnum)
                        {
                            arg = Enum.Parse(byValType, arg.ToString());
                        }
                        else if (byValType.IsInterface)
                        {
                            if (Marshal.IsComObject(arg))
                            {
                                wrapper = originalArgs[i];
                                if (null != wrapper && wrapper._COMObject != arg)
                                {
                                    wrapper.Dispose();
                                    wrapper = null;
                                }

                                if (null == wrapper)
                                {
                                    wrapper = new COMWrapper(arg, byValType);
                                }
                                arg = wrapper.GetTransparentProxy();
                            }
                        }
                        outArgs[i] = arg;
                    }
                }
            }

            return(new ReturnMessage(returnValue, outArgs, outArgsCount, callMessage.LogicalCallContext, callMessage));
        }
        /// <summary>
        /// Intercept method calls
        /// </summary>
        /// <param name="myMessage">
        /// Contains information about the method being called
        /// </param>
        /// <returns>
        /// A <see cref="ReturnMessage"/>.
        /// </returns>
        public override IMessage Invoke(IMessage myMessage)
        {
            IMethodCallMessage callMessage = myMessage as IMethodCallMessage;

            if (null == callMessage)
            {
                LOG.DebugFormat("Message type not implemented: {0}", myMessage.GetType().ToString());
                return(null);
            }

            MethodInfo method = callMessage.MethodBase as MethodInfo;

            if (null == method)
            {
                LOG.DebugFormat("Unrecognized Invoke call: {0}", callMessage.MethodBase.ToString());
                return(null);
            }

            object returnValue = null;

            object[] outArgs      = null;
            int      outArgsCount = 0;

            string       methodName = method.Name;
            Type         returnType = method.ReturnType;
            BindingFlags flags      = BindingFlags.InvokeMethod;
            int          argCount   = callMessage.ArgCount;

            object invokeObject;
            Type   invokeType;
            Type   byValType;

            object[] args;
            object   arg;

            COMWrapper[] originalArgs;
            COMWrapper   wrapper;

            ParameterModifier[] argModifiers = null;
            ParameterInfo[]     parameters   = null;
            ParameterInfo       parameter;

            if ("Dispose" == methodName && 0 == argCount && typeof(void) == returnType)
            {
                Dispose();
            }
            else if ("ToString" == methodName && 0 == argCount && typeof(string) == returnType)
            {
                returnValue = ToString();
            }
            else if ("GetType" == methodName && 0 == argCount && typeof(Type) == returnType)
            {
                returnValue = _InterceptType;
            }
            else if ("GetHashCode" == methodName && 0 == argCount && typeof(int) == returnType)
            {
                returnValue = GetHashCode();
            }
            else if ("Equals" == methodName && 1 == argCount && typeof(bool) == returnType)
            {
                returnValue = Equals(callMessage.Args[0]);
            }
            else if (1 == argCount && typeof(void) == returnType && (methodName.StartsWith("add_") || methodName.StartsWith("remove_")))
            {
                bool removeHandler = methodName.StartsWith("remove_");
                methodName = methodName.Substring(removeHandler ? 7 : 4);

                Delegate handler = callMessage.InArgs[0] as Delegate;
                if (null == handler)
                {
                    return(new ReturnMessage(new ArgumentNullException("handler"), callMessage));
                }
            }
            else
            {
                invokeObject = _COMObject;
                invokeType   = _COMType;

                if (methodName.StartsWith("get_"))
                {
                    // Property Get
                    methodName = methodName.Substring(4);
                    flags      = BindingFlags.GetProperty;
                    args       = callMessage.InArgs;
                }
                else if (methodName.StartsWith("set_"))
                {
                    // Property Set
                    methodName = methodName.Substring(4);
                    flags      = BindingFlags.SetProperty;
                    args       = callMessage.InArgs;
                }
                else
                {
                    args = callMessage.Args;
                    if (null != args && 0 != args.Length)
                    {
                        // Modifiers for ref / out parameters
                        argModifiers    = new ParameterModifier[1];
                        argModifiers[0] = new ParameterModifier(args.Length);

                        parameters = method.GetParameters();
                        for (int i = 0; i < parameters.Length; i++)
                        {
                            parameter = parameters[i];
                            if (parameter.IsOut || parameter.ParameterType.IsByRef)
                            {
                                argModifiers[0][i] = true;
                                outArgsCount++;
                            }
                        }

                        if (0 == outArgsCount)
                        {
                            argModifiers = null;
                        }
                    }
                }

                // Un-wrap wrapped COM objects before passing to the method
                if (null == args || 0 == args.Length)
                {
                    originalArgs = null;
                }
                else
                {
                    originalArgs = new COMWrapper[args.Length];
                    for (int i = 0; i < args.Length; i++)
                    {
                        if (null != args[i] && RemotingServices.IsTransparentProxy(args[i]))
                        {
                            wrapper = RemotingServices.GetRealProxy(args[i]) as COMWrapper;
                            if (null != wrapper)
                            {
                                originalArgs[i] = wrapper;
                                args[i]         = wrapper._COMObject;
                            }
                        }
                        else if (0 != outArgsCount && argModifiers[0][i])
                        {
                            byValType = GetByValType(parameters[i].ParameterType);
                            if (byValType.IsInterface)
                            {
                                // If we're passing a COM object by reference, and
                                // the parameter is null, we need to pass a
                                // DispatchWrapper to avoid a type mismatch exception.
                                if (null == args[i])
                                {
                                    args[i] = new DispatchWrapper(null);
                                }
                            }
                            else if (typeof(Decimal) == byValType)
                            {
                                // If we're passing a decimal value by reference,
                                // we need to pass a CurrencyWrapper to avoid a
                                // type mismatch exception.
                                // http://support.microsoft.com/?kbid=837378
                                args[i] = new CurrencyWrapper(args[i]);
                            }
                        }
                    }
                }

                do
                {
                    try
                    {
                        returnValue = invokeType.InvokeMember(methodName, flags, null, invokeObject, args, argModifiers, null, null);
                        break;
                    }
                    catch (Exception ex)
                    {
                        // Test for rejected
                        COMException comEx = ex as COMException;
                        if (comEx == null)
                        {
                            comEx = ex.InnerException as COMException;
                        }
                        if (comEx != null && (comEx.ErrorCode == RPC_E_CALL_REJECTED || comEx.ErrorCode == RPC_E_FAIL))
                        {
                            string destinationName = _TargetName;
                            // Try to find a "catchy" name for the rejecting application
                            if (destinationName != null && destinationName.Contains("."))
                            {
                                destinationName = destinationName.Substring(0, destinationName.IndexOf("."));
                            }
                            if (destinationName == null)
                            {
                                destinationName = _InterceptType.FullName;
                            }
                            DialogResult result = MessageBox.Show(Language.GetFormattedString("com_rejected", destinationName), Language.GetString("com_rejected_title"), MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);
                            if (result == DialogResult.OK)
                            {
                                continue;
                            }
                        }
                        // Not rejected OR pressed cancel
                        return(new ReturnMessage(ex, callMessage));
                    }
                } while (true);

                // Handle enum and interface return types
                if (null != returnValue)
                {
                    if (returnType.IsInterface)
                    {
                        // Wrap the returned value in an intercepting COM wrapper
                        if (Marshal.IsComObject(returnValue))
                        {
                            returnValue = Wrap(returnValue, returnType, _TargetName);
                        }
                    }
                    else if (returnType.IsEnum)
                    {
                        // Convert to proper Enum type
                        returnValue = Enum.Parse(returnType, returnValue.ToString());
                    }
                }

                // Handle out args
                if (0 != outArgsCount)
                {
                    outArgs = new object[args.Length];
                    for (int i = 0; i < parameters.Length; i++)
                    {
                        if (!argModifiers[0][i])
                        {
                            continue;
                        }

                        arg = args[i];
                        if (null == arg)
                        {
                            continue;
                        }

                        parameter = parameters[i];
                        wrapper   = null;

                        byValType = GetByValType(parameter.ParameterType);
                        if (typeof(Decimal) == byValType)
                        {
                            if (arg is CurrencyWrapper)
                            {
                                arg = ((CurrencyWrapper)arg).WrappedObject;
                            }
                        }
                        else if (byValType.IsEnum)
                        {
                            arg = Enum.Parse(byValType, arg.ToString());
                        }
                        else if (byValType.IsInterface)
                        {
                            if (Marshal.IsComObject(arg))
                            {
                                wrapper = originalArgs[i];
                                if (null != wrapper && wrapper._COMObject != arg)
                                {
                                    wrapper.Dispose();
                                    wrapper = null;
                                }

                                if (null == wrapper)
                                {
                                    wrapper = new COMWrapper(arg, byValType, _TargetName);
                                }
                                arg = wrapper.GetTransparentProxy();
                            }
                        }
                        outArgs[i] = arg;
                    }
                }
            }

            return(new ReturnMessage(returnValue, outArgs, outArgsCount, callMessage.LogicalCallContext, callMessage));
        }
        /// <summary>
        /// Gets or creates a COM object and returns the transparent proxy which intercepts all calls to the object
        /// The ComProgId can be a normal ComProgId or a GUID prefixed with "clsid:"
        /// </summary>
        /// <param name="type">Interface which defines the method and properties to intercept</param>
        /// <returns>Transparent proxy to the real proxy for the object</returns>
        /// <remarks>The <paramref name="type"/> must be an interface decorated with the <see cref="ComProgIdAttribute"/>attribute.</remarks>
        public static T GetOrCreateInstance <T>()
        {
            Type type = typeof(T);

            if (null == type)
            {
                throw new ArgumentNullException("type");
            }
            if (!type.IsInterface)
            {
                throw new ArgumentException("The specified type must be an interface.", "type");
            }

            ComProgIdAttribute progIDAttribute = ComProgIdAttribute.GetAttribute(type);

            if (null == progIDAttribute || null == progIDAttribute.Value || 0 == progIDAttribute.Value.Length)
            {
                throw new ArgumentException("The specified type must define a ComProgId attribute.", "type");
            }

            object comObject = null;
            Type   comType   = null;
            string progId    = progIDAttribute.Value;
            Guid   guid      = Guid.Empty;

            // Convert from clsid to Prog ID, if needed
            if (progId.StartsWith("clsid:"))
            {
                guid = new Guid(progId.Substring(6));
                int result = ProgIDFromCLSID(ref guid, out progId);
                if (result != 0)
                {
                    // Restore progId, as it's overwritten
                    progId = progIDAttribute.Value;
                    try
                    {
                        GetActiveObject(ref guid, IntPtr.Zero, out comObject);
                    }
                    catch (Exception)
                    {
                        LOG.WarnFormat("Error {0} getting instance for class id {1}", result, progIDAttribute.Value);
                    }
                    if (comObject == null)
                    {
                        LOG.WarnFormat("Error {0} getting progId {1}", result, progIDAttribute.Value);
                    }
                }
                else
                {
                    LOG.InfoFormat("Mapped {0} to progId {1}", progIDAttribute.Value, progId);
                }
            }

            if (comObject == null)
            {
                if (!progId.StartsWith("clsid:"))
                {
                    try
                    {
                        comObject = Marshal.GetActiveObject(progId);
                    }
                    catch (COMException comE)
                    {
                        if (comE.ErrorCode == MK_E_UNAVAILABLE)
                        {
                            LOG.DebugFormat("No current instance of {0} object available.", progId);
                        }
                        else if (comE.ErrorCode == CO_E_CLASSSTRING)
                        {
                            LOG.WarnFormat("Unknown progId {0} (application not installed)", progId);
                            return(default(T));
                        }
                        else
                        {
                            LOG.Warn("Error getting active object for " + progId, comE);
                        }
                    }
                    catch (Exception e)
                    {
                        LOG.Warn("Error getting active object for " + progId, e);
                    }
                }
            }

            // Did we get the current instance? If not, try to create a new
            if (comObject == null)
            {
                try
                {
                    comType = Type.GetTypeFromProgID(progId, true);
                }
                catch (Exception ex)
                {
                    if (Guid.Empty != guid)
                    {
                        comType = Type.GetTypeFromCLSID(guid);
                    }
                    else
                    {
                        LOG.Warn("Error type for " + progId, ex);
                    }
                }

                if (comType != null)
                {
                    try
                    {
                        comObject = Activator.CreateInstance(comType);
                        if (comObject != null)
                        {
                            LOG.DebugFormat("Created new instance of {0} object.", progId);
                        }
                    }
                    catch (Exception e)
                    {
                        LOG.Warn("Error creating object for " + progId, e);
                    }
                }
            }
            if (comObject != null)
            {
                if (comObject is IDispatch)
                {
                    COMWrapper wrapper = new COMWrapper(comObject, type, progIDAttribute.Value);
                    return((T)wrapper.GetTransparentProxy());
                }
                else
                {
                    return((T)comObject);
                }
            }
            return(default(T));
        }
Esempio n. 7
0
        /// <summary>
        /// Gets a COM object and returns the transparent proxy which intercepts all calls to the object
        /// </summary>
        /// <typeparam name="T">Interface which defines the method and properties to intercept</typeparam>
        /// <returns>Transparent proxy to the real proxy for the object</returns>
        /// <remarks>T must be an interface decorated with the <see cref="ComProgIdAttribute"/>attribute.</remarks>
        public static T GetInstance <T>()
        {
            Type type = typeof(T);

            if (null == type)
            {
                throw new ArgumentNullException(nameof(T));
            }
            if (!type.IsInterface)
            {
                throw new ArgumentException("The specified type must be an interface.", nameof(T));
            }

            var progIdAttribute = ComProgIdAttribute.GetAttribute(type);

            if (string.IsNullOrEmpty(progIdAttribute?.Value))
            {
                throw new ArgumentException("The specified type must define a ComProgId attribute.", nameof(T));
            }
            string progId = progIdAttribute.Value;

            object comObject = null;

            // Convert from clsid to Prog ID, if needed
            if (progId.StartsWith("clsid:"))
            {
                Guid guid   = new Guid(progId.Substring(6));
                int  result = ProgIDFromCLSID(ref guid, out progId);
                if (result != 0)
                {
                    // Restore progId, as it's overwritten
                    progId = progIdAttribute.Value;

                    try {
                        GetActiveObject(ref guid, IntPtr.Zero, out comObject);
                    } catch (Exception) {
                        Log.WarnFormat("Error {0} getting instance for class id {1}", result, progIdAttribute.Value);
                    }
                    if (comObject == null)
                    {
                        Log.WarnFormat("Error {0} getting progId {1}", result, progIdAttribute.Value);
                    }
                }
                else
                {
                    Log.InfoFormat("Mapped {0} to progId {1}", progIdAttribute.Value, progId);
                }
            }

            if (comObject == null)
            {
                try {
                    comObject = Marshal.GetActiveObject(progId);
                } catch (COMException comE) {
                    if (comE.ErrorCode == MK_E_UNAVAILABLE)
                    {
                        Log.DebugFormat("No current instance of {0} object available.", progId);
                    }
                    else if (comE.ErrorCode == CO_E_CLASSSTRING)
                    {
                        Log.WarnFormat("Unknown progId {0}", progId);
                    }
                    else
                    {
                        Log.Warn("Error getting active object for " + progIdAttribute.Value, comE);
                    }
                } catch (Exception e) {
                    Log.Warn("Error getting active object for " + progIdAttribute.Value, e);
                }
            }

            if (comObject != null)
            {
                if (comObject is IDispatch)
                {
                    COMWrapper wrapper = new COMWrapper(comObject, type, progIdAttribute.Value);
                    return((T)wrapper.GetTransparentProxy());
                }
                else
                {
                    return((T)comObject);
                }
            }
            return(default(T));
        }
Esempio n. 8
0
        /// <summary>
        /// Gets or creates a COM object and returns the transparent proxy which intercepts all calls to the object
        /// The ComProgId can be a normal ComProgId or a GUID prefixed with "clsid:"
        /// </summary>
        /// <typeparam name="T">Interface which defines the method and properties to intercept</typeparam>
        /// <returns>Transparent proxy to the real proxy for the object</returns>
        /// <remarks>The type must be an interface decorated with the <see cref="ComProgIdAttribute"/>attribute.</remarks>
        public static T GetOrCreateInstance <T>()
        {
            Type type = typeof(T);

            if (null == type)
            {
                throw new ArgumentNullException(nameof(T));
            }
            if (!type.IsInterface)
            {
                throw new ArgumentException("The specified type must be an interface.", nameof(T));
            }

            ComProgIdAttribute progIdAttribute = ComProgIdAttribute.GetAttribute(type);

            if (string.IsNullOrEmpty(progIdAttribute?.Value))
            {
                throw new ArgumentException("The specified type must define a ComProgId attribute.", nameof(T));
            }

            object comObject = null;
            Type   comType   = null;
            string progId    = progIdAttribute.Value;

            try {
                comObject = Marshal.GetActiveObject(progId);
            } catch (COMException comE) {
                if (comE.ErrorCode == MK_E_UNAVAILABLE)
                {
                    Debug.WriteLine($"No current instance of {progId} object available.");
                }
                else if (comE.ErrorCode == CO_E_CLASSSTRING)
                {
                    Debug.WriteLine($"Unknown progId {progId}");
                }
            } catch (Exception ex) {
                Debug.WriteLine($"Error getting active object for {progId} {ex.Message}");
            }
            // Did we get the current instance? If not, try to create a new
            if (comObject == null)
            {
                try {
                    comType = Type.GetTypeFromProgID(progId, true);
                } catch (Exception) {
                    Debug.WriteLine($"Error getting type for {progId}");
                }
                if (comType != null)
                {
                    try {
                        comObject = Activator.CreateInstance(comType);
                        if (comObject != null)
                        {
                            Debug.WriteLine($"Created new instance of {progId} object.");
                        }
                    } catch (Exception ex) {
                        Debug.WriteLine($"Error creating object for {progId} {ex.Message}");
                    }
                }
            }
            if (comObject != null)
            {
                COMWrapper wrapper = new COMWrapper(comObject, type);
                return((T)wrapper.GetTransparentProxy());
            }
            return(default(T));
        }
Esempio n. 9
0
        /// <summary>
        /// Intercept method calls 
        /// </summary>
        /// <param name="myMessage">
        /// Contains information about the method being called
        /// </param>
        /// <returns>
        /// A <see cref="ReturnMessage"/>.
        /// </returns>
        public override IMessage Invoke(IMessage myMessage)
        {
            IMethodCallMessage callMessage = myMessage as IMethodCallMessage;
            if (null == callMessage) {
                LOG.DebugFormat("Message type not implemented: {0}", myMessage.GetType().ToString());
                return null;
            }

            MethodInfo method = callMessage.MethodBase as MethodInfo;
            if (null == method) {
                LOG.DebugFormat("Unrecognized Invoke call: {0}", callMessage.MethodBase.ToString());
                return null;
            }

            object returnValue = null;
            object[] outArgs = null;
            int outArgsCount = 0;

            string methodName = method.Name;
            Type returnType = method.ReturnType;
            BindingFlags flags = BindingFlags.InvokeMethod;
            int argCount = callMessage.ArgCount;

            object invokeObject;
            Type invokeType;
            Type byValType;

            object[] args;
            object arg;
            COMWrapper[] originalArgs;
            COMWrapper wrapper;

            ParameterModifier[] argModifiers = null;
            ParameterInfo[] parameters = null;
            ParameterInfo parameter;

            if ("Dispose" == methodName && 0 == argCount && typeof(void) == returnType) {
                this.Dispose();
            } else if ("ToString" == methodName && 0 == argCount && typeof(string) == returnType) {
                returnValue = this.ToString();
            } else if ("GetType" == methodName && 0 == argCount && typeof(System.Type) == returnType) {
                returnValue = this._InterceptType;
            } else if ("GetHashCode" == methodName && 0 == argCount && typeof(int) == returnType) {
                returnValue = this.GetHashCode();
            } else if ("Equals" == methodName && 1 == argCount && typeof(bool) == returnType) {
                returnValue = this.Equals(callMessage.Args[0]);
            } else if (1 == argCount && typeof(void) == returnType && (methodName.StartsWith("add_") || methodName.StartsWith("remove_"))) {
                bool removeHandler = methodName.StartsWith("remove_");
                methodName = methodName.Substring(removeHandler ? 7 : 4);

                Delegate handler = callMessage.InArgs[0] as Delegate;
                if (null == handler) {
                    return new ReturnMessage(new ArgumentNullException("handler"), callMessage);
                }
            } else {
                invokeObject = this._COMObject;
                invokeType = this._COMType;

                if (methodName.StartsWith("get_")) {
                    // Property Get
                    methodName = methodName.Substring(4);
                    flags = BindingFlags.GetProperty;
                    args = callMessage.InArgs;
                } else if (methodName.StartsWith("set_")) {
                    // Property Set
                    methodName = methodName.Substring(4);
                    flags = BindingFlags.SetProperty;
                    args = callMessage.InArgs;
                } else {
                    args = callMessage.Args;
                    if (null != args && 0 != args.Length) {
                        // Modifiers for ref / out parameters
                        argModifiers = new ParameterModifier[1];
                        argModifiers[0] = new ParameterModifier(args.Length);

                        parameters = method.GetParameters();
                        for(int i=0; i<parameters.Length; i++) {
                            parameter = parameters[i];
                            if (parameter.IsOut || parameter.ParameterType.IsByRef) {
                                argModifiers[0][i] = true;
                                outArgsCount++;
                            }
                        }

                        if (0 == outArgsCount) {
                            argModifiers = null;
                        }
                    }
                }

                // Un-wrap wrapped COM objects before passing to the method
                if (null == args || 0 == args.Length) {
                    originalArgs = null;
                } else {
                    originalArgs = new COMWrapper[args.Length];
                    for(int i=0; i<args.Length; i++) {
                        if (null != args[i] && RemotingServices.IsTransparentProxy(args[i])) {
                            wrapper = RemotingServices.GetRealProxy(args[i]) as COMWrapper;
                            if (null != wrapper) {
                                originalArgs[i] = wrapper;
                                args[i] = wrapper._COMObject;
                            }
                        } else if (0 != outArgsCount && argModifiers[0][i]) {
                            byValType = GetByValType(parameters[i].ParameterType);
                            if (byValType.IsInterface) {
                                // If we're passing a COM object by reference, and
                                // the parameter is null, we need to pass a
                                // DispatchWrapper to avoid a type mismatch exception.
                                if (null == args[i]) {
                                    args[i] = new DispatchWrapper(null);
                                }
                            } else if (typeof(Decimal) == byValType) {
                                // If we're passing a decimal value by reference,
                                // we need to pass a CurrencyWrapper to avoid a
                                // type mismatch exception.
                                // http://support.microsoft.com/?kbid=837378
                                args[i] = new CurrencyWrapper(args[i]);
                            }
                        }
                    }
                }

                try {
                    returnValue = invokeType.InvokeMember(methodName, flags, null, invokeObject, args, argModifiers, null, null);
                } catch(Exception ex) {
                    return new ReturnMessage(ex, callMessage);
                }

                // Handle enum and interface return types
                if (null != returnValue) {
                    if (returnType.IsInterface) {
                        // Wrap the returned value in an intercepting COM wrapper
                        if (Marshal.IsComObject(returnValue)) {
                            returnValue = COMWrapper.Wrap(returnValue, returnType);
                        }
                    } else if (returnType.IsEnum) {
                        // Convert to proper Enum type
                        returnValue = Enum.Parse(returnType, returnValue.ToString());
                    }
                }

                // Handle out args
                if (0 != outArgsCount) {
                    outArgs = new object[args.Length];
                    for(int i=0; i<parameters.Length; i++) {
                        if (!argModifiers[0][i]) {
                            continue;
                        }

                        arg = args[i];
                        if (null == arg) {
                            continue;
                        }

                        parameter = parameters[i];
                        wrapper = null;

                        byValType = GetByValType(parameter.ParameterType);
                        if (typeof(Decimal) == byValType) {
                            if (arg is CurrencyWrapper) {
                                arg = ((CurrencyWrapper)arg).WrappedObject;
                            }
                        } else if (byValType.IsEnum) {
                            arg = Enum.Parse(byValType, arg.ToString());
                        } else if (byValType.IsInterface) {
                            if (Marshal.IsComObject(arg)) {
                                wrapper = originalArgs[i];
                                if (null != wrapper && wrapper._COMObject != arg) {
                                    wrapper.Dispose();
                                    wrapper = null;
                                }

                                if (null == wrapper) {
                                    wrapper = new COMWrapper(arg, byValType);
                                }
                                arg = wrapper.GetTransparentProxy();
                            }
                        }
                        outArgs[i] = arg;
                    }
                }
            }

            return new ReturnMessage(returnValue, outArgs, outArgsCount, callMessage.LogicalCallContext, callMessage);
        }
Esempio n. 10
0
        /// <summary>
        /// Wrap an object and return the transparent proxy which intercepts all calls
        /// to the object
        /// </summary>
        /// <param name="comObject">An object to intercept</param>
        /// <param name="type">Interface which defines the method and properties to intercept</param>
        /// <returns>Transparent proxy to the real proxy for the object</returns>
        public static object Wrap(object comObject, Type type)
        {
            if (null == comObject) {
                throw new ArgumentNullException("comObject");
            }
            if (null == type) {
                throw new ArgumentNullException("type");
            }

            COMWrapper wrapper = new COMWrapper(comObject, type);
            return wrapper.GetTransparentProxy();
        }
Esempio n. 11
0
        /// <summary>
        /// Gets a COM object and returns the transparent proxy 
        /// which intercepts all calls to the object
        /// </summary>
        /// <param name="type">Interface which defines the method and properties to intercept</param>
        /// <returns>Transparent proxy to the real proxy for the object</returns>
        /// <remarks>The <paramref name="type"/> must be an interface decorated with the <see cref="ComProgIdAttribute"/>attribute.</remarks>
        public static object GetOrCreateInstance(Type type)
        {
            if (null == type) {
                throw new ArgumentNullException("type");
            }
            if (!type.IsInterface) {
                throw new ArgumentException("The specified type must be an interface.", "type");
            }

            ComProgIdAttribute progID = ComProgIdAttribute.GetAttribute(type);
            if (null == progID || null == progID.Value || 0 == progID.Value.Length) {
                throw new ArgumentException("The specified type must define a ComProgId attribute.", "type");
            }

            object comObject = null;
            Type comType = Type.GetTypeFromProgID(progID.Value, true);
            try {
                comObject = Marshal.GetActiveObject(progID.Value);
            } catch (COMException comE) {
                if (comE.ErrorCode == MK_E_UNAVAILABLE) {
                    LOG.DebugFormat("No current instance of {0} object available.", progID.Value);
                } else {
                    LOG.Warn("Error getting active object for " + progID.Value, comE);
                }
            } catch (Exception e) {
                LOG.Warn("Error getting active object for " + progID.Value, e);
            }
            // Did we get the current instance? If not, try to create a new
            if (comObject == null) {
                try {
                    comObject = Activator.CreateInstance(comType);
                    if (comObject != null) {
                        LOG.DebugFormat("Created new instance of {0} object.", progID.Value);
                    }
                } catch (Exception e) {
                    LOG.Warn("Error creating object for " + progID.Value, e);
                }
            }
            if (comObject != null) {
                COMWrapper wrapper = new COMWrapper(comObject, type);
                return wrapper.GetTransparentProxy();
            }
            throw new TypeLoadException(string.Format("Unable to get or create an instance of the specified COM server \"{0}\".", progID.Value));
        }