DLL中有回调函数,还有结构体DLL中结构体,回调函数和函数的原型如下:typedef struct _VOCLINK_PARAM {
TCHAR sVocIp[16];
UINT nPort;
} VOCLINK_PARAM, *PVOCLINK_PARAM;typedef struct _VMCCB_EVT {
UINT EvtCode;
UINT RetCode;
UINT Channel;
UINT uBufferLen; // pBuffer 's length
void* pBuffer; // Buffer for holding extra info
} VMCCB_EVT, *PVMCCB_EVT;typedef void (*VLVMC_CB)( long VocHandle, const PVMCCB_EVT pVmcEvt, LPARAM lpData );_DLLIMP long CALL_CONVENT
VLVmcOpen( const VLVMC_CB pVmcCB, LPARAM lpData, long *pVmcHandle );_DLLIMP long CALL_CONVENT
VLVmcConnectVoc( long VmcHandle, const PVOCLINK_PARAM pVocSrv, long *pVocHandle );C#中对应类型定义如下:  public static class VMCOperator
        {
            /// Return Type: int
            ///pVmcCB: VLVMC_CB
            ///lpData: LPARAM->LONG_PTR->int
            ///pVmcHandle: int*
            [DllImportAttribute("VLVmc.dll", EntryPoint = "VLVmcOpen", CallingConvention = CallingConvention.StdCall)]
            //public static extern int VLVmcOpen(VLVMC_CB pVmcCB, [MarshalAsAttribute(UnmanagedType.SysInt)] int lpData, ref int pVmcHandle);
            public static extern int VLVmcOpen(VLVMC_CB pVmcCB, int lpData, ref int pVmcHandle);            /// Return Type: int
            ///VmcHandle: int
            [DllImportAttribute("VLVmc.dll", EntryPoint = "VLVmcClose", CallingConvention = CallingConvention.StdCall)]
            public static extern int VLVmcClose(int VmcHandle);            /// Return Type: int
            ///VmcHandle: int
            ///pVocSrv: PVOCLINK_PARAM->_VOCLINK_PARAM*
            ///pVocHandle: int*
            [DllImportAttribute("VLVmc.dll", EntryPoint = "VLVmcConnectVoc", CallingConvention = CallingConvention.StdCall)]
            public static extern int VLVmcConnectVoc(int VmcHandle, ref VOCLINK_PARAM pVocSrv, ref int pVocHandle);            /// Return Type: int
            ///VocHandle: int
            [DllImportAttribute("VLVmc.dll", EntryPoint = "VLVmcDisconnectVoc", CallingConvention = CallingConvention.StdCall)]
            public static extern int VLVmcDisconnectVoc(int VocHandle);        }
        [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
        public struct VOCLINK_PARAM
        {            /// TCHAR[16]
            [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 16)]
            public string sVocIp;
            //public char* sVocIp;            /// UINT->unsigned int
            public uint nPort;
        }        [StructLayoutAttribute(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 IntPtr pBuffer;
        }        /// Return Type: void
        ///VocHandle: int
        ///pVmcEvt: PVMCCB_EVT->_VMCCB_EVT*
        ///lpData: LPARAM->LONG_PTR->int
        //[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        public delegate void VLVMC_CB(int VocHandle, ref VMCCB_EVT pVmcEvt, int lpData);调用函数的代码:        private void btnOpenVMC_Click(object sender, RoutedEventArgs e)
        {
            vmc_handler = 0;
            int lpdata = 0;            if (VMCOperator.VLVmcOpen(vmc_cb, lpdata, ref vmc_handler) == VLVMC_ERR_SUCCESS)
            {
                MessageBox.Show("VMC Opened");
                voc_link_param.sVocIp = "192.168.4.44";
                voc_link_param.nPort = 3000;
                voc_handler = 0;
                if (VMCOperator.VLVmcConnectVoc(vmc_handler,ref voc_link_param, ref voc_handler) == VLVMC_ERR_SUCCESS)
                {
                    MessageBox.Show("Voice Connected");
                }
            }
        }        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            vmc_cb = new VLVMC_CB(OnVLVMC_CB);
            voc_link_param = new VOCLINK_PARAM();
            vmccb_evt = new VMCCB_EVT();
        }
        private void OnVLVMC_CB(int voc_handler, ref VMCCB_EVT vmccb_evt, int lpdata)
        {
            MessageBox.Show(vmccb_evt.EvtCode.ToString());
        }在调用VLVmcConnectVoc函数时就报错:尝试读取或写入受保护的内存。这通常指示其他内存已损坏。
看了网上有人加上了委托的属性 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
可是这样做虽然不报错了,但结果不对,不知道是不是封送 sVocIp 出错造成的,请高手指点迷津在线等,谢谢!

解决方案 »

  1.   

    TChar类型应对应于C#中得byte数组类型    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
        public struct VOCLINK_PARAM
        {
            /// TCHAR[16]
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            public byte[] sVocIp;        /// UINT->unsigned int
            public uint nPort;
        }string类型与byte类型转换string vocip = “192.168.4.44”;
    byte[] bytevocip = new byte[16];
    Encoding.Default.GetBytes(vocip).CopyTo(bytevocip, 0);
      

  2.   

    TChar不一定是对应byte
    根据你的C++ DLL编译条件
    若是使用了Unicode则TCHAR是WCHAR,双字节了
      

  3.   

    确实。
    因此,一般不是使用CharSet.Auto,而是指定CharSet.ANSI或CharSet.Unicode
    然后:
      /// TCHAR[16]
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
      public String sVocIp;
      

  4.   

    但是有两个问题
    1、我不知道在定义结构体时到底指定ANSI还是Unicode
    2、传入一个IP,程序会报错,说是读取了不安全的地址
      

  5.   

    读取 了不安全的地址一般都是传到C++ DLL的指针访问越界或指向错误了,
    C++里的数据类型和C#里的有驱动,比如根据编译格式不同,有的占一个字节有的占两个字节