当前位置:编程学习 > C#/ASP.NET >>

急求解法,C#调用COM,传递数组参数的问题,谢谢~

这几天捉摸在C#里面调用COM的问题,数组参数怎么也传不过去,dll动态加载和静态加载的方法都试过了,未果。
函数原型 
STDMETHODIMP CComplexTypeTest::ArrayTest2(int a[], int length)
{
for(int i=0;i<10;i++)
          printf("%d\t",a[i]);
getchar();
return S_OK;
}
1》静态加载的方法中,
 int[] arrays = new int[10];
 for (int i = 0; i < 10; i++)
                arrays[i] = i + 3;
cTestObject.ArrayTest2(ref arrays[0], 10);
结果输出来的数据不对,只有第一个是对的。
2》用DllImport的方法,包装函数后调用。
 [DllImport("E:\\软件测试\\DataTypeTest2\\Debug\\DataTypeTest2.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "ArrayTest2")]
        public static extern void ArrayTest2(IntPtr a,int length);
调用时候用(这个方法是书上看的)
int[] arrays = new int[10];
for (int i = 0; i < 10; i++)
     arrays[i] = i + 3;
IntPtr a = IntPtr.Zero;
IntPtr valueArr = Marshal.AllocCoTaskMem(10 * arrays[0]);
for (int i = 0; i < 10; i++)
{
a = (IntPtr)((int)valueArr + i * Marshal.SizeOf(arrays[0]));
Marshal.WriteInt32(a, arrays[i]);
}
            
TestStructureDll.ArrayTest2(valueArr, 10);
Marshal.FreeCoTaskMem(valueArr);
结果输出还是不正确,并且出现说PInvoke签名错误,不知道为啥,大家在传送数组的时候是怎么做的呀?托管和非托管真是麻烦呀。
请高手指点,时间比较紧张,急求解法! --------------------编程问答-------------------- COM的dll是你自己写的吗?参数类型改成(int* a,int length)试试~~~
--------------------编程问答-------------------- 是自己写的,我也改成了(int* a,int length),依然挂。
是不是ref只传过去一个数据,而后面的数据没有跟着一起过去呀?应该用动态还是静态调用的啊? --------------------编程问答-------------------- 关注一下!~~ --------------------编程问答--------------------
引用 2 楼 curieloveyou 的回复:
是自己写的,我也改成了(int* a,int length),依然挂。 
是不是ref只传过去一个数据,而后面的数据没有跟着一起过去呀?应该用动态还是静态调用的啊?



设断点调试一把就知道怎么回事了~~~ --------------------编程问答-------------------- 记得注册表里dll的路径先写成你调试的路径,搞定了再把dll放到windows 目录下去,当然你也可以放在其他路径~~~~ --------------------编程问答-------------------- 学习,我也碰到这个问题了
lz解决没有? --------------------编程问答-------------------- 既然是调用COM,为什么还要用DllImport呢?

COM公布的函数并不需要是导出函数,COM的激活和调用是另外一种机制。 --------------------编程问答-------------------- int* 和int[]其实是一样的,数组做参数会退化成指针的。

楼主想用PInvoke的方法,应该这样用PInvoke传递数组:

[MarshalAs(UnmanagedType.LPArray, SizeConst = 4)]int Array[]


我觉得用调用COM的话,应该用NETtoCOM的Marshall的方法,相关知识可以看一下msdn中Marshall。

--------------------编程问答-------------------- 学习.... --------------------编程问答-------------------- 对于楼主的问题可以这样解决:

.NET调用COM的方法:
第一步,注册COM server, regsvr32 *.dll(这个事进程内服务器)
第二步,

using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

[ComImport, Guid("E587FEE6-F270-4B66-B568-C69694FB2B16"),CoClass(typeof(VarComSvr2Lib.VarSvr2Class)), TypeLibType((short)0x10c0)]
    public interface IVarServer2 : VarComSvr2Lib.IVarSvr2
    {
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(1)]
        bool ArrayTest2([MarshalAs(UnmanagedType.LPArray), SizeConst = 10]int[] intArray, int length);
    }



这是Import一个COM接口

第三步调用要用的方法,有两种方法:

早绑定(early bound)


int[] intArr = new int[10];
IVarServer2 svr_earlybound = new IVarServer2();
svr_earlybound.ArrayTest2(intArr, 10);


晚绑定(late bound)

Type typeSvr = Type.GetTypeFromProgID("VarComSvr2.VarSvr2");
object svr_latebound = Activator.CreateInstance(typeSvr);

                int[] paramarr = new int[1];

                ParameterModifier p = new ParameterModifier(1);
                p[0] = true;
                ParameterModifier[] mods = { p };
                System.Boolean vt_value = false;
                paramarr[0] = vt_value;

                bool retBool = (bool)typeSvr.InvokeMember(
                    "TakeVar_VT_BOOL_AsParamByRef",
                    BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance,
                    null,
                    svr_latebound,
                    paramarr,
                    mods,
                    null,
                    null
                    );

不过貌似VS2008中不可以对数组进行晚绑定。

希望这些对楼主有帮助。 --------------------编程问答-------------------- 你的问题主要就是COM Interop过程中的数据封送问题。楼上有人已经给出了正确的答案。但是如果只获得答案,不知道原理,以后遇到了此类问题还是不知道如何下手。

如果你想系统学习如何进行数据封送,我推荐你阅读刚刚出版的新书:《精通.NET互操作P/Invoke,C++Interop和COM Interop》,这本书的第5,6章都详细讲述了COM Interop中的数据封送处理,非常详细,我就是读完后才搞清楚COM Interop的。 


该书的官方网站: 
www.interop123.com 

豆瓣网信息: 
http://www.douban.com/subject/3671497/  --------------------编程问答-------------------- 帮顶,也遇到这问题了,正四处解决,感谢楼上的提供的网址,里面找到了个电子书,正在看 --------------------编程问答-------------------- 还是没有解决方法吗?书我也找过了,里面似乎没有提到用传递字符串数组到COM里去的示例嘛,有也是在COM那头用的是SAFEARRAY的,没有提到C Style --------------------编程问答-------------------- 楼主我把问题解决了,不仅是可直接复制到非托管的数据类型,字符串数组问题也解决了~~~快现身 --------------------编程问答-------------------- 这个问题我也遇到了,有点技术,我是用C#调用ocx控件传递数组参数,搞了两天终于成功了
ocx是用vc写的,这里关键是用safearray,再用variant包装safearray
c#用object传递数组

哪位要实例代码,可以联系我bob98bob@sohu.com --------------------编程问答-------------------- ding    
补充:.NET技术 ,  C#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,