我这有个C++的头文件和转换到C#里引用的文件,哪位大哥愿意帮我看看有没错误(因为编译没错,部分函数调用也没错,之前其中一个函数出现了“ 尝试读取或写入受保护的内存。这通常指示其他内存已损坏” 这个错误,今天另一个函数也出现这样错误了,小弟十分不解,求详细解答)。#include "Windows.h"#define SMS_BUF_TOTAL 50
#define SMS_FORMAT_PDU 0  //PDU模式(中文短信模式)
#define SMS_FORMAT_TEXT 1  //Text模式(拉丁语系短信模式)struct SM_PARAM
{
    char SCA[16];       // 短消息服务中心号码(SMSC地址)
    char TPA[30];       // 目标号码或回复号码(TP-DA或TP-RA)
    char TP_PID;        // 用户信息协议标识(TP-PID)
    char TP_DCS;        // 用户信息编码方式(TP-DCS)
    char TP_SCTS[16];   // 服务时间戳字符串(TP_SCTS), 接收时用到
    char TP_UD[161];    // 原始用户信息(编码前或解码后的TP-UD)
    char index;         // 短消息序号,在读取时用到
};struct SM_RCV_STRU
{
    int iSmsTotal; //已收到的短信条数
    struct SM_PARAM SMS[SMS_BUF_TOTAL]; //存储pdu串参数
};struct STRUCommInfo
{
    int iBaudRate; //比特率
    char szSCA[30]; //短信中信号码
};typedef SM_RCV_STRU RCVMSG;
typedef STRUCommInfo SIMINFO;
//获取版本信息,储存在szRetVer中。 发送和接收短信都可要可不要
extern _declspec(dllexport) void __stdcall WINAPI GetVerInfo(char* szRetVer);//验证GSM的用户名和序列号,发送短信必须验证成功,接收短信则可以不验证。 验证不匹配则返回-100.
extern _declspec(dllexport) int __stdcall WINAPI iCheck(char* szCorp,char* szInputSN);//打开串口
extern _declspec(dllexport) HANDLE __stdcall WINAPI hOpenComm(const char *szPort);// 关闭成功但是不会使句柄无效
extern _declspec(dllexport) bool __stdcall WINAPI bCloseComm(HANDLE hComm);//获取串口信息    hComm为已经打开的串口句柄  STRUCommInfo用来存储信息的结构体,iSMSFormat为信息编码格式,szErrInfo为得到的错误信息
extern _declspec(dllexport) bool __stdcall WINAPI bAutoInit(HANDLE hComm,STRUCommInfo *CommInfo,int iSMSFormat,char *szErrInfo);//清空SIM卡上信息 
extern _declspec(dllexport) bool __stdcall WINAPI bClrSIM(HANDLE hComm,char *szErrInfo);//发送信息
//参数含义: hComm串口句柄 szMsgs发送的信息内容   zOhNbr目标号码 szSCA短信中心号码 szNextMsg存放未发出信息的内容地址 iSMSFormat信息编码格式 szErrorInfo存放返回的错误信息
//返回值: 发送成功与否
extern _declspec(dllexport) bool __stdcall WINAPI bSendMsg(HANDLE hComm,char *szMsg,char *szPhNbr,char *szSCA,char *szNextMsg,int iSMSFormat,char *szErrInfo);

//接收信息  
//参数含义: hComm串口句柄 RcvSMS存储接收到的信息的PDU串参数 iSMSFormat信息编码格式 szErrorInfo存放返回的错误信息
//返回值: 接收到的信息数目
extern _declspec(dllexport) int __stdcall WINAPI iRecvMsg(HANDLE hComm,SM_RCV_STRU *RcvSMS,int iSMSFormat,char *szErrInfo);extern _declspec(dllexport) bool __stdcall WINAPI bSendWapPush(HANDLE hComm,char* szPhNbr,char* szWapTitle, char* szWapUrl,char *szErrInfo);
   public const int SMS_BUF_TOTAL = 50;
    public const int SMS_FORMAT_PDU = 0;  //PDU模式(中文短信模式)
    public const int SMS_FORMAT_TEXT = 1;  //Text模式(拉丁语系短信模式)    [StructLayout(LayoutKind.Sequential)]
    public struct SM_PARAM
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public char[] SCA;           // 短消息服务中心号码(SMSC地址)
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)]
        public char[] TPA;          // 目标号码或回复号码(TP-DA或TP-RA)
        public char TP_PID;           // 用户信息协议标识(TP-PID)
        public char TP_DCS;           // 用户信息编码方式(TP-DCS)
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public char[] TP_SCTS;       // 服务时间戳字符串(TP_SCTS), 接收时用到
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 161)]
        public char[] TP_UD;       // 原始用户信息(编码前或解码后的TP-UD)
        public char index;         // 短消息序号,在读取时用到
    };    [StructLayout(LayoutKind.Sequential)]
    public struct SM_RCV_STRU
    {
        public int iSmsTotal; //已收到的短信条数
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = GSM.SMS_BUF_TOTAL)]
        public SM_PARAM[] SMS;                         //存储pdu串参数
    };    [StructLayout(LayoutKind.Sequential)]
    public struct STRUCommInfo
    {
        public int iBaudRate; //比特率
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)]
        public char[] szSCA; //短信中信号码
    };
    //获取版本信息,储存在szRetVer中。 发送和接收短信都可要可不要
    [DllImport("dsmscom.dll", SetLastError = true)]
    public static extern void GetVerInfo(ref string strRetVerInfo);    //验证GSM的用户名和序列号,发送短信必须验证成功,接收短信则可以不验证。 验证不匹配则返回-100.
    [DllImport("dsmscom.dll", SetLastError = true)]
    public static extern int iCheck(string strCorp, string strInputSN);    //打开指定的串口
    [DllImport("dsmscom.dll", SetLastError = true)]
    public static extern IntPtr hOpenComm(string strCommNum);    // 关闭成功但是不会使句柄无效
    [DllImport("dsmscom.dll", SetLastError = true)]
    public static extern bool bCloseComm(IntPtr hComm);    //获取串口信息    hComm为已经打开的串口句柄  STRUCommInfo用来存储信息的结构体,iSMSFormat为信息编码格式,szErrInfo为得到的错误信息
    [DllImport("dsmscom.dll", SetLastError = true)]
    public static extern bool bAutoInit(IntPtr hComm, ref STRUCommInfo CommInfo, int iSMSFormat, ref string strErrInfo);    //清空SIM卡上信息 
    [DllImport("dsmscom.dll", SetLastError = true)]
    public static extern bool bClrSIM(IntPtr hComm, ref string strErrInfo);    //发送信息
    //参数含义: hComm串口句柄 szMsgs发送的信息内容 strPhNbr目标号码 szSCA短信中心号码 szNextMsg存放未发出信息的内容地址 iSMSFormat信息编码格式 szErrorInfo存放返回的错误信息
    //返回值: 发送成功与否
    [DllImport("dsmscom.dll", SetLastError = true)]
     public static extern bool bSendMsg(IntPtr hComm, string strMsg, string strPhNbr, string strSCA, ref string strNextMsg, int iSMSFormat, ref string strErrInfo);
    //参数含义: hComm串口句柄 RcvSMS存储接收到的信息的PDU串参数 iSMSFormat信息编码格式 szErrorInfo存放返回的错误信息
    //返回值: 接收到的信息数目
    [DllImport("dsmscom.dll", SetLastError = true)]
    public static extern int iRecvMsg(IntPtr hComm, ref SM_RCV_STRU RcvSMS, int iSMSFormat, ref string strErrInfo);
以前出现这个问题时 调用bool bRet = GSM.bAutoInit(hComm, ref CommInfo, iSmsFormat, ref strErrInfo);没出错,出错的是GSM.bSendMsg(hComm, strTmpMsg, strTmpSndPh, strSCA, ref strTmpNextMsg, GSM.SMS_FORMAT_PDU, ref strErrInfo);    
当时我把bSendMsg函数的引用和调用部分的ref都去掉了就没问题了。  这次出现 bAutoInit 函数调用出现这样的错误了。。麻烦大家积极解答,谢谢了!!

解决方案 »

  1.   

    对于char*输出的参数用[Out] StringBuilder ,如
    public static extern bool bAutoInit(IntPtr hComm, ref STRUCommInfo CommInfo, int iSMSFormat, [Out] StringBuilder strErrInfo);
    试试
      

  2.   

    尝试读取或写入受保护的内存。这通常指示其他内存已损坏,是因为dll里的方法要写回数据,但是你传给它的是一个受保护的内存
      

  3.   

    刚才试了下,还是不行。   其实以前调用bSndMsg函数时,我就那样改过,也是不行的。
    我把函数调用部分的代码也给你看
          
                    GSM.STRUCommInfo CommInfo = new GSM.STRUCommInfo(); //存储GSM比特率和SIM卡短信中心号码的结构体
                    int iSmsFormat = GSM.SMS_FORMAT_PDU;                     //信息编码格式
                    //string strErrInfo = "";
                    StringBuilder sbErrInfo = new StringBuilder();
                    bool bRet = GSM.bAutoInit(hComm, ref CommInfo, iSmsFormat,out sbErrInfo);     //获取串口信息另外对于bSndMsg函数,我是把定义部分和调用部分的ref都去掉了,反而没提示错误了,这个地方估计是函数内部写的都是形式参数了,所以没出错了。但是这样就破坏了函数的功能了。不知道怎么解决。
      

  4.   

    你直接用:
    public static extern bool bAutoInit(IntPtr hComm, ref STRUCommInfo CommInfo, int iSMSFormat, [Out] StringBuilder strErrInfo);
    这样调用试试bool bRet = GSM.bAutoInit(hComm, ref CommInfo, iSmsFormat,sbErrInfo);
      

  5.   

    把bAutoInit最后一个参数的ref去掉,关键要看最后一个参数是否是返回值,是否在dll内部被改写
      

  6.   

    因该是参数的问题,不能有改变变量作用域的关键字,例如ref、out,在C#中要去掉
      

  7.   

    out加上[] 是什么意思? 这种调用方法会提示参数类型不匹配
      

  8.   


    ASP.NET有这个吗? 我没找到啊
      

  9.   

    我并没有使用指针啊
    最后一个参数就是用来返回错误描述的,去掉ref虽然能运行了,但是函数的功能损失掉了啊
    为什么要去掉呢?   ref 和out不就是C#里为了方便返回值用的吗?
      

  10.   


    strErrInfo 调用时候要预先分配足够的内存如:strErrInfo  = "足够的内存";
      

  11.   

    字符串形式的也需要事先开辟足够多的内存吗?
    我用 string strErrInfo = new string(' ',100);也不行啊
      

  12.   

    string strErrInfo = new string(' ',1000);这样的话貌似可以,进一步确认中。
      

  13.   

    你给看下这个函数 extern _declspec(dllexport) bool    __stdcall WINAPI bSendMsg(HANDLE hComm,char *szMsg,char *szPhNbr,char *szSCA,char *szNextMsg,int iSMSFormat,char *szErrInfo);[DllImport("dsmscom.dll", SetLastError = true)]
         public static extern bool bSendMsg(IntPtr hComm, string strMsg, string strPhNbr, string strSCA, ref string strNextMsg, int iSMSFormat, ref string strErrInfo);我改成这么调用        //发送信息
            string strTmpMsg = strMsg;        string strTmpNextMsg = strMsg; //保存上次没发完的信息        string strTmpSndPh = strDesNum;      //目标号码,前面的86可要可不要        string strError = new string(' ',1000);        //发送信息
            while (strTmpMsg.Length > 0)
            {            if (string.IsNullOrEmpty(strTmpNextMsg))
                    strTmpNextMsg.Remove(0, strTmpNextMsg.Length);
                if (string.IsNullOrEmpty(strError))
                    strError.Remove(0, strError.Length);            //发送strTmpMsg中的信息,strTmpNextMsg中存放没发送出去的内容
                bool bRet = GSM.bSendMsg(hComm, strTmpMsg, strTmpSndPh, strSca,ref strTmpNextMsg, GSM.SMS_FORMAT_PDU,ref strError);//尝试读取或写入受保护的内存。这通常指示其他内存已损坏。每次运行到这个函数就自动退出整个系统了。。 网页上显示连接失败。。