下面的C++接口,我用DELPHI对接,调用时报内存异常,麻烦各位大侠帮忙看一下:C++接口定义:struct STUMsgProperty 2 { 
char m_szSourceUserID[MR 2_MAXLEN_ADDR]; 
char m_szSourceAppID[MR 2_MA XLEN_ADDR]; 
char m_szDestUserID[MR 2_MAXLEN_ADDR]; 
char m_szDestAppID[MR 2_MAXLEN_ADDR]; 
char m_szPkgID[MR 2_MAXLEN_PKGID]; 
char m_szCorrPkgID[MR 2_MAXLEN_PKGID]; 
char m_szUserData 1[MR 2_MAXLEN_USERDATA]; 
char m_szUserData2[MR 2_MAXLEN_USERDATA]; 
unsigned char m_ucFlag; 
unsigned char m_uc Biz Type; 
unsigned char m_ucPriority; 
unsigned char m_ucSensitiveLevel; 
char m_szMsgType[MR2_MAXLEN_MSGTYPE]; 
};int _stdcall Mr 2Receive3(void* pHandle, char** ppsPkg, int * piOutPkgLen, int* piErrSXCode, STUMsgProperty 2* pMsgPropery, int iMillSecTimeo) ;
参数 说明
pHandle [in] 连接句柄。
ppsPkg [out] 双指针,返回包所向的内存。
piOutPkgLen [out] 接收到的消息包实际长度。
piErrSXCode[out] 交换错误的原因码.
pMsgPropery [in/out] 输入将作为接收条件,输出是接收到的包属性。
iMillSecTimeo [in] 以毫秒为单位的接收最大时间。Delphi代码:type
  pSTUMsgProperty2 = ^TSTUMsgProperty2;
  TSTUMsgProperty2 = record
    m_szSourceUserID: array[1..MR2_MAXLEN_ADDR] of AnsiChar; 
    m_szSourceAppID: array[1..MR2_MAXLEN_ADDR] of AnsiChar; 
    m_szDestUserID: array[1..MR2_MAXLEN_ADDR] of AnsiChar;
    m_szDestAppID: array[1..MR2_MAXLEN_ADDR] of AnsiChar;
    m_szPkgID: array[1..MR2_MAXLEN_PKGID] of AnsiChar; 
    m_szCorrPkgID: array[1..MR2_MAXLEN_PKGID] of AnsiChar;
    m_szUserData1: array[1..MR2_MAXLEN_USERDATA] of AnsiChar; 
    m_szUserData2: array[1..MR2_MAXLEN_USERDATA] of AnsiChar;
    m_ucFlag: word; 
    m_ucBizType: word; 
    m_ucPriority: word; 
    m_ucSensitiveLevel: word; 
    m_szMsgType: array[1..MR2_MAXLEN_MSGTYPE] of AnsiChar;
  end;type
  TMr2RecvFunc = function(_pMr2InitHandle: PHandle; const ppsPkg: PPAnsiChar; piOutPkgLen: Pinteger; piErrSXCode: Pinteger; pMsgPropery: pSTUMsgProperty2; iMillSecTimeo: integer):integer;stdcall;function Mr2Receive: Integer;
var
  pMr2Recv: TMr2RecvFunc;
  FileStream: TFileStream;
  FileBuffer: PPAnsiChar;
  piOutPkgLen, piErrSXCode: pinteger;
  pMsgPropery: pSTUMsgProperty2;
  MsgPropery: TSTUMsgProperty2;
begin
  Result := -1;  if pMr2InitHandle = nil then
  begin
    ShowMessage('请先初始化Mr2!');
    Exit;
  end;  if not Assigned(@pMr2Recv) then
    @pMr2Recv := GetProcAddress(Mr2Handle, 'Mr2Receive3');  if Assigned(@pMr2Recv) then
  begin
    new(pMsgPropery);
    Result := pMr2Recv(pMr2InitHandle, FileBuffer,piOutPkgLen, piErrSXCode, pMsgPropery, 2000);//这一步报内存写异常
    Dispose(pMsgPropery);
  end;
end;

解决方案 »

  1.   

    TMr2RecvFunc = function(_pMr2InitHandle: PHandle; var ppsPkg: PPAnsiChar; piOutPkgLen: Pinteger; piErrSXCode: Pinteger; pMsgPropery: pSTUMsgProperty2; iMillSecTimeo: integer):integer;stdcall;
      

  2.   

    双指针可以定义成^PChar
      

  3.   

    就是PPChar喽?
    赋值有什么要注意的么?
      

  4.   

    指针参数可以转化为变参,从而(形式上)脱去一级指针:int _stdcall Mr 2Receive3(void* pHandle, char** ppsPkg, int * piOutPkgLen, int* piErrSXCode, STUMsgProperty 2* pMsgPropery, int iMillSecTimeo) ;TMr2RecvFunc = function(var _pMr2InitHandle: THandle; var ppsPkg: PAnsiChar; var piOutPkgLen: integer; var piErrSXCode: integer; var pMsgPropery: TSTUMsgProperty2; iMillSecTimeo: integer):integer;stdcall; 
      

  5.   


    TMr2RecvFunc = function(_pMr2InitHandle: PHandle; var ppsPkg: PAnsiChar; var piOutPkgLen: integer; var piErrSXCode: integer; var pMsgPropery: TSTUMsgProperty2; iMillSecTimeo: integer):integer;stdcall; function Mr2Receive: Integer;
    var
      pMr2Recv: TMr2RecvFunc;
      FileBuffer: PAnsiChar;
      piOutPkgLen, piErrSXCode: integer;
      MsgPropery: TSTUMsgProperty2;
    begin
      Result := -1;  if not Assigned(@pMr2Recv) then
        @pMr2Recv := GetProcAddress(Mr2Handle, 'Mr2Receive3');  if Assigned(@pMr2Recv) then
      begin
        GetMem(FileBuffer,4096);
        new(pMsgPropery);
        try
          Result := pMr2Recv(pMr2InitHandle, FileBuffer,piOutPkgLen, piErrSXCode, MsgPropery, 2000);
        except    end;
        freeMem(FileBuffer);
        Dispose(pMsgPropery);
      end;end;上面的代码还是报错,是初始化有问题么?
      

  6.   

    pMr2InitHandle应该先有一个初始化过程吧,诸如有个openxxx函数返回一个handle。
      

  7.   


    pMr2InitHandle是全局变量,已经有值的。
    pMr2InitHandle = pMr2Init(ConfigMsg.AppID, ConfigMsg.AppPasswd, nil, @ConfigMsg.STUConnInfo, 2, PAnsiChar(''));
      

  8.   

    pMr2Init返回值是一个指针?
      

  9.   


    是的,发送数据、断开连接的接口都需要用到这个值,调用时没有发现问题。
    但是我用pMr2InitHandle^取到的值是1,不知道是什么原因。
      

  10.   



    以下蓝色部分是C++的DEMO,用的MR2RECEIVE1:
    typedef int   (WINAPI MR2RECEIVE1)(void*, char**, int*, STUMsgProperty2*, int);
    typedef int   (WINAPI MR2RECEIVE3)(void*, char**, int*, int*, STUMsgProperty2*, int);unsigned __stdcall RecvThrd(void *pvParam)
    {
        int iLastGetOk = 0;
        for(;;)
        {
            STUMsgProperty2 oMsgPropery;
            memset(&oMsgPropery, '\0', sizeof(STUMsgProperty2));        int iRecvPkgLen = 0;
            char* psPkg = NULL;
    int iRet = Mr2Receive1(g_pHandle, &psPkg, &iRecvPkgLen, &oMsgPropery, 1000);
            if(iRet==0)
            {
                g_ltLastTimeRecv = time(NULL);
                ++g_iRecvCount;
                if(g_iRecvCount%100==0)
                {
                    printf("recv ok: PkgContent[%s]\n, pkgID[%s], src[%s.%s], dest[%s.%s], pkgLen[%d], CorrPkgID[%s], UserData1[%s], UserData2[%s] \n", psPkg, oMsgPropery.m_szPkgID, oMsgPropery.m_szSourceUserID, oMsgPropery.m_szSourceAppID, oMsgPropery.m_szDestUserID, oMsgPropery.m_szDestAppID, iRecvPkgLen, oMsgPropery.m_szCorrPkgID, oMsgPropery.m_szUserData1, oMsgPropery.m_szUserData2);
                    printf("client recv count[%d]\n", g_iRecvCount);
                }#ifndef MR_CLIENT
                STUMsgProperty2 oMsgProperySend;
                memset(&oMsgProperySend, '\0', sizeof(STUMsgProperty2));
                strcpy(oMsgProperySend.m_szDestUserID, oMsgPropery.m_szSourceUserID);
                strcpy(oMsgProperySend.m_szDestAppID, oMsgPropery.m_szSourceAppID);
                strcpy(oMsgProperySend.m_szCorrPkgID, oMsgPropery.m_szPkgID);
                strcpy(oMsgProperySend.m_szUserData1, oMsgPropery.m_szUserData1);
                strcpy(oMsgProperySend.m_szUserData2, oMsgPropery.m_szUserData2);
                oMsgProperySend.m_ucFlag = 0;
                int iRet = Mr2Send(g_pHandle, psPkg, iRecvPkgLen, &oMsgProperySend, 2000);
    #endif
                Mr2Receive1_FreeBuf(psPkg);
            }
            else
            {
                MySleep(500);
            }
        }
        return 0;
    }
    我现在想在DELPHI里调用MR2RECEIVE3,跟MR2RECEIVE1比就多了一个参数,麻烦再帮忙看一下哈。
      

  11.   

    这里g_pHandle是一个指针:
    int iRet = Mr2Receive1(g_pHandle, &psPkg, &iRecvPkgLen, &oMsgPropery, 1000);
    那么:
    TMr2RecvFunc = function(_pMr2InitHandle: pointer; var ppsPkg: PAnsiChar; var piOutPkgLen: integer; var piErrSXCode: integer; var pMsgPropery: TSTUMsgProperty2; iMillSecTimeo: integer):integer;stdcall; 
      

  12.   

    @DelphiGuy 发私信了,麻烦帮忙看一下哈。
    谢谢!真的很着急。
      

  13.   

    #11的声明应该是没有问题的,
    只是这个
    int iRet = Mr2Receive1(g_pHandle, &psPkg, &iRecvPkgLen, &oMsgPropery, 1000);
    g_pHandle是怎么得到的还得看他的例子代码,可能是你获取的不对。
      

  14.   


    这个是C++ DEMO中的初始化过程:
    typedef void *(WINAPI MR2INIT)(const char*, const char*, int, const STUConnInfo2*, void *);
    void*   g_pHandle = NULL;int main(int argc, char* argv[])
    {
    if (!LoadDll())
    {
    printf("load mrapi.dll error.\n");
    return -1;
    }

    string ssSourceUserID, ssSourceAppID, ssDestUserID, ssDestAppID;
        string ssName1 = "FTCSTEST91";
        string ssName2 = "app8";
        string ssName3 = "FTCSTEST92";
        string ssName4 = "app6";
    #ifdef MR_CLIENT
        ssSourceUserID = ssName1;
        ssSourceAppID = ssName2;
        ssDestUserID = ssName3;
        ssDestAppID = ssName4;
    #else
        ssSourceUserID = ssName3;
        ssSourceAppID = ssName4;
        ssDestUserID = ssName1;
        ssDestAppID = ssName2;
    #endif    g_ltLastTimeRecv = time(NULL);    string ssMyPasswd = "1";
        string *pUserData = new string("hello");    STUConnInfo2  oConnInfo[2];
        memset(&oConnInfo, 0, 2*sizeof(STUConnInfo2));
        if(argc<2) strcpy(oConnInfo[0].m_szMRIP, "127.0.0.1");
        else strcpy(oConnInfo[0].m_szMRIP, argv[1]);
        oConnInfo[0].m_usMRPort = 1001;
        strcpy(oConnInfo[1].m_szMRIP, "127.0.0.1");
        oConnInfo[1].m_usMRPort = 3001;    g_pHandle = Mr2Init(ssSourceAppID.c_str(), ssMyPasswd.c_str(), NULL, &oConnInfo, 2, pUserData);
    if(g_pHandle==NULL) return -1;
    /*
        STUMsgProperty2 oOnRecvMsgPropery;
        memset(&oOnRecvMsgPropery, 0, sizeof(STUMsgProperty2));
        strcpy(oOnRecvMsgPropery.m_szCorrPkgID, "<EMPTY>");
        Mr2Init2(&g_pHandle, ssSourceAppID.c_str(), ssMyPasswd.c_str(), &oOnRecvMsgPropery, (int)OnReceive, &oConnInfo, 2, pUserData, 1);
        if(g_pHandle==NULL) return -1;*/
        if(_beginthreadex(NULL, 0,  RecvThrd, NULL, 0, NULL)==0)
        {
            printf("create thread failed\n");
            return -1;
        }    printf("\n");
        MySleep(2000);
        g_ltLastTimeRecv = time(NULL);#ifdef MR_CLIENT
    #else    for(;;MySleep(1000))
        {
        }
    #endif    Mr2Destroy(g_pHandle);
        printf("End\n");    return 0;
    }
    下面是DELPHI代码:
    type TMr2InitFunc = function(const psAppID: PAnsiChar; const psPasswd:PAnsiChar; OnReceive:PInteger; const pArrConnInfo:pSTUConnInfo2; iArrConnInfoCount: Integer; pvUserData:PAnsiChar):Pointer;stdcall;function Mr2Init: Pointer;
    var
      pMr2Init: TMr2InitFunc;
    begin
      Result := nil;  if Mr2Handle = 0 then
      begin
        PrintLog('请先加载mrapi.dll!');
        Exit;
      end;  @pMr2Init := GetProcAddress(Mr2Handle, 'Mr2Init');
      if Assigned(@pMr2Init) then
      begin
        GetConfigMsg;
        
        Result := pMr2Init(ConfigMsg.AppID, ConfigMsg.AppPasswd, nil, @ConfigMsg.STUConnInfo, 2, PAnsiChar(''));
      end;
    end;
      

  15.   

    原型
    typedef void *(WINAPI MR2INIT)(const char*, const char*, int, const STUConnInfo2*, void *);
    和实际调用
     g_pHandle = Mr2Init(ssSourceAppID.c_str(), ssMyPasswd.c_str(), NULL, &oConnInfo, 2, pUserData);
    对不上啊。type TMr2InitFunc = function(const psAppID: PAnsiChar; const psPasswd:PAnsiChar; OnReceive:PInteger; const pArrConnInfo:pSTUConnInfo2; iArrConnInfoCount: Integer; pvUserData:PAnsiChar):Pointer;stdcall;
    是根据什么翻译的?
      

  16.   

    1. 接口文档定义(delph声明是根据这个来的):
    void* _stdcall Mr2Init(const char* psAppID, const char* psPasswd, int (*OnRe ceive 2)(const char* psPkg, int iPkgLe n, const STUMsgProperty 2* pMsgPropery , void* pvUserData), const STUConnInfo 2* pArrC onnInfo , int iArrConnInfoCount , void* pvUserData);int _stdcall Mr2Receive3(void* pHandle, char** ppsPkg, int * piOutPkgLen, int* piErrSXCode, STUMsgProperty 2* pMsgPropery, int iMillSecTimeo) ;2. C++ DEMO代码:
    声明:
    typedef void *(WINAPI MR2INIT)(const char*, const char*, int, const STUConnInfo2*, void *);
    typedef int   (WINAPI MR2RECEIVE3)(void*, char**, int*, int*, STUMsgProperty2*, int);
    变量定义
    MR2INIT      *Mr2Init;
    MR2RECEIVE3 *Mr2Receive3;
    HINSTANCE m_ghDll;
    void*   g_pHandle = NULL;
    加载DLL
    m_ghDll = ::LoadLibrary(MRAPI_DLL) ;
    if (m_ghDll == NULL)
    {
    printf(“error: can not find (mrapi.dll).”) ;
    return bRet ;
    }
    Mr2Init = (MR2INIT *)::GetProcAddress(m_ghDll, "Mr2Init") ;
    if (Mr2Init == NULL)
    {
    printf(“error: can not find Mr2Init(mrapi.dll)”) ;
    ::FreeLibrary(m_ghDll) ;
    m_ghDll = NULL ;
    return bRet ;
    }
    Mr2Receive3 = (MR2RECEIVE3 *)::GetProcAddress(m_ghDll, "Mr2Receive3") ;
    if (Mr2Receive3 == NULL)
    {
    printf(“error: can not find Mr2Receive3(mrapi.dll)”) ;
    ::FreeLibrary(m_ghDll) ;
    m_ghDll = NULL ;
    return bRet ;
    }
    主程序
    string ssSourceUserID, ssSourceAppID, ssDestUserID, ssDestAppID;
        string ssName1 = "FTCSTEST91";
        string ssName2 = "app8";
        string ssName3 = "FTCSTEST92";
        string ssName4 = "app6";
    #ifdef MR_CLIENT
        ssSourceUserID = ssName1;
        ssSourceAppID = ssName2;
        ssDestUserID = ssName3;
        ssDestAppID = ssName4;
    #else
        ssSourceUserID = ssName3;
        ssSourceAppID = ssName4;
        ssDestUserID = ssName1;
        ssDestAppID = ssName2;
    #endif    g_ltLastTimeRecv = time(NULL);    string ssMyPasswd = "1";
        string *pUserData = new string("hello");    STUConnInfo2  oConnInfo[2];
        memset(&oConnInfo, 0, 2*sizeof(STUConnInfo2));
        if(argc<2) strcpy(oConnInfo[0].m_szMRIP, "127.0.0.1");
        else strcpy(oConnInfo[0].m_szMRIP, argv[1]);
        oConnInfo[0].m_usMRPort = 1001;
        strcpy(oConnInfo[1].m_szMRIP, "127.0.0.1");
        oConnInfo[1].m_usMRPort = 3001;    g_pHandle = Mr2Init(ssSourceAppID.c_str(), ssMyPasswd.c_str(), NULL, &oConnInfo, 2, pUserData);
    if(g_pHandle==NULL) return -1;
    /*
        STUMsgProperty2 oOnRecvMsgPropery;
        memset(&oOnRecvMsgPropery, 0, sizeof(STUMsgProperty2));
        strcpy(oOnRecvMsgPropery.m_szCorrPkgID, "<EMPTY>");
        Mr2Init2(&g_pHandle, ssSourceAppID.c_str(), ssMyPasswd.c_str(), &oOnRecvMsgPropery, (int)OnReceive, &oConnInfo, 2, pUserData, 1);
        if(g_pHandle==NULL) return -1;*/
        if(_beginthreadex(NULL, 0,  RecvThrd, NULL, 0, NULL)==0)
        {
            printf("create thread failed\n");
            return -1;
        }
    线程
    unsigned __stdcall RecvThrd(void *pvParam)
    {
        int iLastGetOk = 0;
        for(;;)
        {
            STUMsgProperty2 oMsgPropery;
            memset(&oMsgPropery, '\0', sizeof(STUMsgProperty2));        int iRecvPkgLen = 0;
            char* psPkg = NULL;
    int iRet = Mr2Receive1(g_pHandle, &psPkg, &iRecvPkgLen, &oMsgPropery, 1000);
            if(iRet==0)
            {
                g_ltLastTimeRecv = time(NULL);
                ++g_iRecvCount;
                if(g_iRecvCount%100==0)
                {
                    printf("recv ok: PkgContent[%s]\n, pkgID[%s], src[%s.%s], dest[%s.%s], pkgLen[%d], CorrPkgID[%s], UserData1[%s], UserData2[%s] \n", psPkg, oMsgPropery.m_szPkgID, oMsgPropery.m_szSourceUserID, oMsgPropery.m_szSourceAppID, oMsgPropery.m_szDestUserID, oMsgPropery.m_szDestAppID, iRecvPkgLen, oMsgPropery.m_szCorrPkgID, oMsgPropery.m_szUserData1, oMsgPropery.m_szUserData2);
                    printf("client recv count[%d]\n", g_iRecvCount);
                }#ifndef MR_CLIENT
                STUMsgProperty2 oMsgProperySend;
                memset(&oMsgProperySend, '\0', sizeof(STUMsgProperty2));
                strcpy(oMsgProperySend.m_szDestUserID, oMsgPropery.m_szSourceUserID);
                strcpy(oMsgProperySend.m_szDestAppID, oMsgPropery.m_szSourceAppID);
                strcpy(oMsgProperySend.m_szCorrPkgID, oMsgPropery.m_szPkgID);
                strcpy(oMsgProperySend.m_szUserData1, oMsgPropery.m_szUserData1);
                strcpy(oMsgProperySend.m_szUserData2, oMsgPropery.m_szUserData2);
                oMsgProperySend.m_ucFlag = 0;
                int iRet = Mr2Send(g_pHandle, psPkg, iRecvPkgLen, &oMsgProperySend, 2000);
    #endif
                Mr2Receive1_FreeBuf(psPkg);
            }
            else
            {
                MySleep(500);
            }
        }
        return 0;
    }
      

  17.   

    这是怎么回事?
    1. 接口文档定义(delph声明是根据这个来的):
    void* _stdcall Mr2Init(const char* psAppID, const char* psPasswd, int (*OnRe ceive 2)(const char* psPkg, int iPkgLe n, const STUMsgProperty 2* pMsgPropery , void* pvUserData), const STUConnInfo 2* pArrC onnInfo , int iArrConnInfoCount , void* pvUserData);另外你编译一下他的C++ DEMO,看看能不能通过?我估计是不行的,因为函数声明和实际调用的参数个数都不一样嘛。
      

  18.   

    我问过对方,int (*OnReceive 2)(const char* psPkg, int iPkgLen, const STUMsgProperty 2* pMsgPropery , void* pvUserData)是一个回调函数指针,可以不用它,所以直接给了个nil值。
    C++我没环境……看能不能想办法试试。
      

  19.   

    可以声明成var ppsPkg:PAnsichar或者ppsPkg : PPAnsiChar