首页 新闻 会员 周边

非托管和托管交互的问题.

0
悬赏园豆:100 [已关闭问题]

这是非托管代码封装的结构体:

 typedef struct structural_MEDIA_MOTION_INFO

         {                                             

         DWORD dwEnable;

         DWORD dwRangeCount;

         DWORD dwRange[3][4];

         DWORD dwSensitive[3];

         } MEDIA_MOTION_INFO;

 

这是非托管代码中的函数原型:

void KGetMotionInfo(HANDLE h, MEDIA_MOTION_INFO* MotionInfo)

 

做法一:

把非托管结构体封装成托管结构体

[StructLayout(LayoutKind.Sequential, Pack=1)]

        public struct MediaMotionInfo

        {

            public Int32 dwEnable;

            public Int32 dwRangeCount;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public int[] dwRange;

            [MarshalAs(UnmanagedType.ByValArray,SizeConst = 3)] public int[] dwSensitive;

        }

 

 

因为非托管代码要求地址传递(MEDIA_MOTION_INFO*),所以本处用(ref MediaMotionInfo

/// <summary>

        /// Get the Servers Motion setting value.

        /// </summary>

        /// <param name="h">[in] The handle returned by KOpenInterface()</param>

        /// <param name="MotionInfo">[out] the Motion information on the video server.</param>

        [DllImport(DLLFILE, EntryPoint = "KGetMotionInfo")]

        public static extern void GetMotionInfo(IntPtr h,ref MediaMotionInfo MotionInfo);

 

调用结果正确 mmi属性是[out],所以可以得到正确的结果结构体。

private void getMotionButton_Click(object sender, EventArgs e)

        {

                mmi = new Acti10000Sdk.MediaMotionInfo();

                Acti10000Sdk.GetMotionInfo(h, ref mmi);

            }

        }

 

 

解决方法二:

我把非托管的结构体封装成一个类,结构如下:

[StructLayout(LayoutKind.Sequential, Pack = 1)]

public class MediaMotionInfo

{

    public Int32 dwEnable;

    public Int32 dwRangeCount;

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]

    public int[] dwRange=new int[12];

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]

    public int[] dwSensitive=new int[3];

}

 

由于我封装的是个类,所以直接写MediaMotionInfo就是引用类型,我认为此处和非托管代码也是匹配的。

/// <summary>

        /// Get the Servers Motion setting value.

        /// </summary>

        /// <param name="h">[in] The handle returned by KOpenInterface()</param>

        /// <param name="MotionInfo">[out] the Motion information on the video server.</param>

        [DllImport(DLLFILE, EntryPoint = "KGetMotionInfo")]

        public static extern void GetMotionInfo(IntPtr h,  MediaMotionInfo MotionInfo);

 

此处参数为一个类的引用,指向堆的上的对象。问题是这样做为什么得不到返回的对象呢?

private void getMotionButton_Click(object sender, EventArgs e)

        {

                mmi = new Acti10000Sdk.MediaMotionInfo();

                Acti10000Sdk.GetMotionInfo(h, mmi);

            }

        }

 

 

问题:第二种方法哪里错了。

问题补充: http://www.cnblogs.com/blue-th/archive/2008/09/25/1298940.html 由于发失败了.所以大家到上面链接看吧,然后到这里回答问题. 不好意思啊
blue th的主页 blue th | 初学一级 | 园豆:110
提问于:2008-09-25 16:34
< >
分享
其他回答(2)
0

看不全,而且字太小

@@ | 园豆:120 (初学一级) | 2008-09-25 16:39
0

似乎第二种应该写为:

        [DllImport(DLLFILE, EntryPoint = "KGetMotionInfo")]

        public static extern void GetMotionInfo(IntPtr h,  [Out]MediaMotionInfo MotionInfo);

Colin Han | 园豆:3041 (老鸟四级) | 2008-09-25 18:33
0

我认为主要问题在这里:

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]

    public int[] dwRange=new int[12];

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]

    public int[] dwSensitive=new int[3];

上面两个数组,在struct里面,这两个数组被分配到了dwRangeCount之后的连续地址中,也就是说在struct 所对应的堆栈中地址分配是这样的:

dwEnable 4bytes

dwRangeCount 4bytes

dwRange 12*4 bytes

dwSensitive 3*4 bytes

而在class 里面,两个数组是作为引用类型存在的,也就是说class的内存中dwRangeCount 和 dwSensitive 的位置并不是值,而是引用。这是本质区别。

在class所对应的管理堆中地址分配是这样的:

dwEnable 4bytes

dwRangeCount 4bytes

dwRange 4 bytes ->指向dwRange 数组在管理堆中所在的实际位置

dwSensitive 4 bytes ->指向dwSensitive 数组在管理堆中所在的实际位置

 

 

 

 

 

 

 

 

 

eaglet | 园豆:17139 (专家六级) | 2008-09-26 08:31
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册