C#调C++写的DLL里的一个函数原型是:
_DLLIMP long CALL_CONVENT VLVmcConnectVoc(
   long VmcHandle,
   const PVOCLINK_PARAM pVocSrv,
   long* pVocHandle
);其中结构体 VOCLINK_PARAM 的定义是typedef struct _VOCLINK_PARAM{
   TCHAR sVocIp[16];
   UINT nPort;
}VOCLINK_PARAM,*PVOCLINK_PARAM;我在C#里定义了结构体 VoiceLinkParam[StructLayout(LayoutKind.Sequential)]
struct VoiceLinkParam
{
   public byte[] voiceip;
   public uint port;
}调用如下:VoiceLinkParam voice_link_param = new VoiceLinkParam();
string voiceip = "192.168.4.44";
voice_link_param.port = 3000;
int voc_handle = 0;
int voc_connect_result = ClassVMC.VLVmcConnectVoc(vmc_handle,ref voice_link_param, ref voc_handle);
if (voc_connect_result == VMC_ERR_SUCCESS)
{
   MessageBox.Show("Connect Voice Success.");
}
else
{
   MessageBox.Show("Connect Voice fail.Result=" + voc_connect_result);
}
class ClassVMC
{
   [DllImport("VLVmc.dll", EntryPoint = "VLVmcConnectVoc")]
   public static extern int VLVmcConnectVoc(int vmc_handle,ref VoiceLinkParam voc_param, ref int voc_handle);
}
可是程序在红色处报错:尝试读取或写入受保护的内存。这通常指示其他内存已损坏;估计是C#结构体定义的问题,正确的结构体定义应该是怎么的呢,请高手指点!

解决方案 »

  1.   

    自己解决了现在分享一下,我的全部代码如下:using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Runtime.InteropServices;namespace NetMoniterWPFApp
    {
        /// <summary>
        /// MainWindow.xaml 的交互逻辑
        /// </summary>
        public partial class MainWindow : Window
        {
            private const int VMC_ERR_SUCCESS = 0;        public MainWindow()
            {
                InitializeComponent();
            }        private void button1_Click(object sender, RoutedEventArgs e)
            {
                getReturn();
            }
            private int GetSum(int a, int b)
            {
                return (a + b);
            }
            private void getReturn()
            {
                try
                {
                    ClassVMC.VLVMC_CB vlvmc_cb = new ClassVMC.VLVMC_CB(OnVLVMCCallBack);
                    int vmc_handle = 0;
                    int lparam = 0;
                    int vmc_open_result = ClassVMC.VLVmcOpen(vlvmc_cb, lparam, ref vmc_handle);
                    if (vmc_open_result == VMC_ERR_SUCCESS)
                    {
                        VOCLINK_PARAM voice_link_param = new VOCLINK_PARAM();
                        voice_link_param.sVocIp = "192.168.4.44";
                        voice_link_param.nPort = 3000;
                        int voc_handle = 0;
                        int voc_connect_result = ClassVMC.VLVmcConnectVoc(vmc_handle, ref voice_link_param, ref voc_handle);
                        if (voc_connect_result == VMC_ERR_SUCCESS)
                        {
                            MessageBox.Show("Connect Voice Success.");
                        }
                        else
                        {
                            MessageBox.Show("Connect Voice fail.Result=" + voc_connect_result);
                        }
                    }
                    else
                    {
                        MessageBox.Show("Open VMC fail.Result=" + vmc_open_result);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }        }
            private void OnVLVMCCallBack(int voice_handle, ref VMCCB_EVT vmccb_evt, int lparam)
            {
                //MessageBox.Show(vmccb_evt.EvtCode.ToString());
            }        private void button2_Click(object sender, RoutedEventArgs e)
            {
                int database = 0x1000;
                int value = database + 2011;
                MessageBox.Show(value.ToString());
            }
        }    class ClassSum
        {
            public delegate int d_SumAll(int a, int b);
            public int SumAll(d_SumAll d_sumall)
            {
                return d_sumall(1, 2);
            }
        }
        class ClassVMC
        {
            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
            public delegate void VLVMC_CB(int voice_handle, ref VMCCB_EVT vmccb_evt, int lparam);
            [DllImport("VLVmc.dll", EntryPoint = "VLVmcOpen")]
            public static extern int VLVmcOpen(VLVMC_CB vlvmc_cb, int lparam, ref int vmc_handle);
            [DllImport("VLVmc.dll", EntryPoint = "VLVmcClose")]
            public static extern int VLVmcClose(int vmc_handle);
            [DllImport("VLVmc.dll", EntryPoint = "VLVmcConnectVoc")]
            public static extern int VLVmcConnectVoc(int vmc_handle, ref VOCLINK_PARAM voc_param, ref int voc_handle);
        }
        [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        public struct VOCLINK_PARAM
        {        /// TCHAR[16]
            [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 16)]
            public string sVocIp;        /// UINT->unsigned int
            public uint nPort;
        }
        [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
        public struct VMCCB_EVT
        {        /// UINT->unsigned int
            public uint EvtCode;        /// UINT->unsigned int
            public uint RetCode;        /// UINT->unsigned int
            public uint Channel;        /// UINT->unsigned int
            public uint uBufferLen;        /// void*
            public System.IntPtr pBuffer;
        }
    }说明:C#动态调用C++的DLL最烦人的莫过于数据类型和机构体的定义了,
    C++类型到C#类型的转换在网上一搜就是一堆,在这里我就不多说了。
    另外有一个非常有用的工具可帮助生成C#下对应的定义代码 winsiggen.exe 
    这里可以下载 http://download.csdn.net/detail/zyx_hawk/2258107我原来的代码主要是少了控制回调函数的特性
     [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
      

  2.   


    一个一个调试,问题都可以解决!“我原来的代码主要是少了控制回调函数的特性
     [UnmanagedFunctionPointer(CallingConvention.Cdecl)]”有点决定很奇怪,如果是这个原因产生,应该是报调用约定的错误,
    怎么会报“尝试读取或写入受保护的内存”,因为这种错误一般由于参数不一致所产生的
      

  3.   

    c#调用C++写的DLL的时候经常需要在托管代码和非托管代码中间做切换,一般的带有返回值的,结构体或指针什么的都现在获得非托管代码内存指针,返回的结果放在指针指向的内存中,然后再将该内存空间的数据赋值到托管代码中的对象中。是挺麻烦的。