コード例 #1
0
        private static Exception GetErrorToLog(Exception e)
        {
            if (e == null)
            {
                throw new ArgumentNullException("e");
            }

            var comException = e as COMException;

            if (comException == null)
            {
                return(e);
            }

            try
            {
                COMSurvivableException.RethrowAsOriginalIfPossible(comException);
            }
            catch (Exception comSurvivableException)
            {
                return(comSurvivableException);
            }
            return(e);
        }
コード例 #2
0
        private static T Invoke <T>(object source, InvokeFlags invokeFlags, int dispId, params object[] args)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            if (!Enum.IsDefined(typeof(InvokeFlags), invokeFlags))
            {
                throw new ArgumentOutOfRangeException("invokeFlags");
            }
            if (args == null)
            {
                throw new ArgumentNullException("args");
            }

            var    memoryAllocationsToFree = new List <IntPtr>();
            IntPtr rgdispidNamedArgs;
            int    cNamedArgs;

            if ((invokeFlags == InvokeFlags.DISPATCH_PROPERTYPUT) || (invokeFlags == InvokeFlags.DISPATCH_PROPERTYPUTREF))
            {
                // There must be at least one argument specified; only one if it is a non-indexed property and multiple if there are index values as well as the
                // value to set to
                if (args.Length < 1)
                {
                    throw new ArgumentException("At least one argument must be specified when DISPATCH_PROPERTYPUT is requested");
                }

                var pdPutID = Marshal.AllocCoTaskMem(sizeof(Int64));
                Marshal.WriteInt64(pdPutID, DISPID_PROPERTYPUT);
                memoryAllocationsToFree.Add(pdPutID);

                rgdispidNamedArgs = pdPutID;
                cNamedArgs        = 1;
            }
            else
            {
                rgdispidNamedArgs = IntPtr.Zero;
                cNamedArgs        = 0;
            }

            var    variantsToClear = new List <IntPtr>();
            IntPtr rgvarg;

            if (args.Length == 0)
            {
                rgvarg = IntPtr.Zero;
            }
            else
            {
                // We need to allocate enough memory to store a variant for each argument (and then populate this memory)
                rgvarg = Marshal.AllocCoTaskMem(SizeOfNativeVariant * args.Length);
                memoryAllocationsToFree.Add(rgvarg);
                for (var index = 0; index < args.Length; index++)
                {
                    // Note: The "IDispatch::Invoke method (Automation)" page (http://msdn.microsoft.com/en-us/library/windows/desktop/ms221479(v=vs.85).aspx)
                    // states that "Arguments are stored in pDispParams->rgvarg in reverse order" so we'll reverse them here
                    var arg = args[(args.Length - 1) - index];

                    // According to http://stackoverflow.com/a/1866268 it seems like using ToInt64 here will be valid for both 32 and 64 bit machines. While
                    // this may apparently not be the most performant approach, it should do the job.
                    // Don't think we have to worry about pinning any references when we do this manipulation here since we are allocating the array in
                    // unmanaged memory and so the garbage collector won't be moving anything around (and GetNativeVariantForObject copies the reference
                    // and automatic pinning will prevent the GC from interfering while this is happening).
                    var pVariant = new IntPtr(
                        rgvarg.ToInt64() + (SizeOfNativeVariant * index)
                        );
                    Marshal.GetNativeVariantForObject(arg, pVariant);
                    variantsToClear.Add(pVariant);
                }
            }

            var dispParams = new ComTypes.DISPPARAMS()
            {
                cArgs             = args.Length,
                rgvarg            = rgvarg,
                cNamedArgs        = cNamedArgs,
                rgdispidNamedArgs = rgdispidNamedArgs
            };

            try
            {
                var    IID_NULL = new Guid("00000000-0000-0000-0000-000000000000");
                UInt32 pArgErr  = 0;
                object varResult;
                var    excepInfo = new ComTypes.EXCEPINFO();
                var    hrRet     = ((IDispatch)source).Invoke
                                   (
                    dispId,
                    ref IID_NULL,
                    LOCALE_SYSTEM_DEFAULT,
                    (ushort)invokeFlags,
                    ref dispParams,
                    out varResult,
                    ref excepInfo,
                    out pArgErr
                                   );
                if (hrRet != 0)
                {
                    if (excepInfo.bstrDescription == null)
                    {
                        Console.WriteLine($"Exception thrown while accessing {TypeDescriptor.GetClassName(source)} has null bstrDescription");
                    }
                    else
                    {
                        Console.WriteLine($"Exception thrown while accessing {TypeDescriptor.GetClassName(source)} has bstrDescription: \"{excepInfo.bstrDescription}\"");
                    }

                    // Try to translate the exception back into a COMSurvivableException - if this is not possible then fall through to the code below
                    COMSurvivableException.RethrowAsOriginalIfPossible(
                        new COMException(excepInfo.bstrDescription, excepInfo.scode)
                        );
                    var message   = "Failing attempting to invoke method with DispId " + dispId + ": ";
                    var errorType = GetErrorMessageForHResult(hrRet);
                    if (errorType == CommonErrors.DISP_E_MEMBERNOTFOUND)
                    {
                        message += "Member not found";
                    }
                    else if (!string.IsNullOrWhiteSpace(excepInfo.bstrDescription))
                    {
                        message += excepInfo.bstrDescription;
                    }
                    else
                    {
                        message += "Unspecified error";
                        if (errorType != CommonErrors.Unknown)
                        {
                            message += " [" + errorType.ToString() + "]";
                        }
                    }
                    throw new ArgumentException(message);
                }
                return((T)varResult);
            }
            finally
            {
                foreach (var variantToClear in variantsToClear)
                {
                    VariantClear(variantToClear);
                }

                foreach (var memoryAllocationToFree in memoryAllocationsToFree)
                {
                    Marshal.FreeCoTaskMem(memoryAllocationToFree);
                }
            }
        }