使用ICustomQueryInterface实现IDispatch。设置属性 - 不工作

时间:2014-10-20 05:27:38

标签: c# com

演示示例:

Echo.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;

namespace EchoProject
{
    [ComVisible(true)]
    [ProgId("EchoProject.Echo")]
    [ClassInterface(ClassInterfaceType.None)]
    public class Echo : IDispatch, ICustomQueryInterface
    {
        private int lastDispId = 0;
        private Dictionary<int, string> dispIdNameMap = new Dictionary<int, string>();

        public CustomQueryInterfaceResult GetInterface(ref Guid iid, out IntPtr ppv)
        {
            ppv = IntPtr.Zero;
            if (typeof(IDispatch).GUID == iid)
            {
                ppv = Marshal.GetComInterfaceForObject(this, typeof(IDispatch), CustomQueryInterfaceMode.Ignore);
                return CustomQueryInterfaceResult.Handled;
            }
            return CustomQueryInterfaceResult.NotHandled;
        }

        public void GetTypeInfoCount(out uint pctinfo)
        {
            pctinfo = 0;
        }

        public void GetTypeInfo(uint iTInfo, int lcid, out IntPtr info)
        {
            info = IntPtr.Zero;
        }

        public void GetIDsOfNames(ref Guid iid, string[] names, int cNames, int lcid, int[] rgDispId)
        {
            for (int i = 0; i < cNames; i++ )
            {
                KeyValuePair<int, string> pair = dispIdNameMap.SingleOrDefault(p => p.Value == names[i]);
                if (pair.Key == 0)
                {
                    dispIdNameMap.Add(++lastDispId, names[i]);
                    rgDispId[i] = lastDispId;
                }
                else
                {
                    rgDispId[i] = pair.Key;
                }
            }
        }

        public void Invoke(int dispId, ref Guid riid, int lcid, System.Runtime.InteropServices.ComTypes.INVOKEKIND wFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, out object result, IntPtr pExcepInfo, IntPtr puArgErr)
        {
            string name;
            dispIdNameMap.TryGetValue(dispId, out name);
            result = name;
        }
    }
}

IDispatch.cs:

using System;
using System.Runtime.InteropServices;

namespace EchoProject
{
    [ComImport]
    [Guid("00020400-0000-0000-C000-000000000046")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IDispatch
    {
        void GetTypeInfoCount(out uint pctinfo);

        void GetTypeInfo(uint iTInfo, int lcid, out IntPtr info);

        void GetIDsOfNames(
            ref Guid iid,
            [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 2)]
                string[] names,
            int cNames,
            int lcid,
            [Out][MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I4, SizeParamIndex = 2)]
                int[] rgDispId);

        void Invoke(
            int dispId,
            ref Guid riid,
            int lcid,
            System.Runtime.InteropServices.ComTypes.INVOKEKIND wFlags,
            ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams,
            out object result,
            IntPtr pExcepInfo,
            IntPtr puArgErr);
    }
}

echo.js:

var echo = new ActiveXObject("EchoProject.Echo");
WScript.Echo("Begin debug");
WScript.Echo(echo.foo()); //foo
WScript.Echo(echo.bar); //bar
echo.baz = 1; //error

调用方法“foo” - 工作。 获得物业“酒吧” - 工作。 设置属性“baz” - 不工作!!!

我尝试使用.NET框架版本:4.5; 4.5.1; 4.5.2 - 设置属性不起作用

有什么问题?

1 个答案:

答案 0 :(得分:1)

您应该像这样更改Invoke定义:

void Invoke(
            int dispId,
            ref Guid riid,
            int lcid,
            System.Runtime.InteropServices.ComTypes.INVOKEKIND wFlags,
            ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams,
            [Out, MarshalAs(UnmanagedType.LPArray)] object[] result,
            IntPtr pExcepInfo,
            IntPtr puArgErr);

并像这样使用它:

public void Invoke(int dispId, ref Guid riid, int lcid, System.Runtime.InteropServices.ComTypes.INVOKEKIND wFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, out object result, IntPtr pExcepInfo, IntPtr puArgErr)
{
    string name;
    dispIdNameMap.TryGetValue(dispId, out name);
    if (result != null)
    {
        result[0] = name;
    }
}