dll里面有个函数是这样写的   registerErrorMessage(PFNERRORCALLBACK pfnErrorMessage);   其中PFNERRORCALLBACK 的定义是  typedef void (*PFNERRORCALLBACK)(ERRORMSGTYPE, char*);   ERRORMSGTYPE是一个枚举  enum ERRORMSGTYPE
 {
  ERRORMSG_INFO,
  ERRORMSG_WARNING,
  ERRORMSG_ERROR,
  ERRORMSG_FATAL
 };
  我使用vb调用该函数,vb中声明这样写Declare Function registerErrorMessage Lib "B2BAPIDLL.dll" (ByVal pfnErrorMessage As Long) As Long回调函数这样写Public Sub ErrorMessageCallback(enErrorType As ERRORMSGTYPE, lpszMsg As Long)
    Debug.Print lpszMsg
    Call Form1.UpdateErrorMessage(enErrorType, lpszMsg)
End Sub其中ERRORMSGTYPE为枚举结构Public Enum ERRORMSGTYPE
    ERRORMSG_INFO
    ERRORMSG_WARNING
    ERRORMSG_ERROR
    ERRORMSG_FATAL
End Enum但是在调试的时候,每当我跟踪岛回调函数,想看enErrorType 变量值时,都会发送访问出错,我想问一下其中发生了什么事

解决方案 »

  1.   

    加上ByVal
    Public Sub ErrorMessageCallback(ByVal enErrorType As ERRORMSGTYPE,ByVal lpszMsg As Long)
    End Sub
      

  2.   

    哦,是这样,但是我发现dll传过来的值变了,例如dll调用回调函数是赋值
    ERRORMSG_INFO,但是我在vb跟踪回调函数enErrorType得到值是3,另外lpszMsg 字段
    为错误描述字符串地址,vb怎么才能取得其内容
      

  3.   

    enErrorType=3也就是enErrorType=ERRORMSG_FATAL,可能哪里出了问题吧获得字符串可以这样:'从指针获得ANSI字符串
    Public Function StrFromPtr(ByVal lpString As Long) As String
        On Error Resume Next
        StrFromPtr = String(1024, Chr(0))
        CopyMemory ByVal StrFromPtr, ByVal lpString, Len(StrFromPtr)
        StrFromPtr = Left(StrFromPtr, InStr(StrFromPtr, Chr(0)) - 1)
    End Function
      

  4.   

    确实是这样,还有一个问题,dll里面有几个函数
    1:setenv()
    2:registerRateUpdate(PFNRATECALLBACK pfnRateConsumer)
    3:registerErrorMessage(PFNERRORCALLBACK pfnErrorMessage)
    4:ReportMessage(ERRORMSGTYPE enErrorType, char* szMsg);
    前三个都是export的函数,第四个的定义是这样
             ReportMessage(ERRORMSGTYPE enErrorType, char* szMsg)
             {
      if (m_pfnErrorCallback)
    m_pfnErrorCallback(enErrorType, szMsg);
             }
    其中m_pfnErrorCallback是PFNERRORCALLBACK 类型回调函数
    dll中setenv和registerRateUpdate函数体内都会调用多个ReportMessage报告运行信息。
    在vb程序中,我在sub main调用registerErrorMessage后,跟踪dll执行到首个ReportMessage
    时m_pfnErrorCallback是我在vb里写的回调函数,但是跟踪到第二个ReportMessage就报告内存读写错误信息了
      

  5.   

    说一下跟踪情况,用vb跟踪,到了回调函数结束就弹出那出不能为read的错误,用vc跟踪
    dll源码,m_pfnErrorCallback在第一次ReportMessage结束,地址就变了,不知道为什么
      

  6.   

    注释后还是不成功,我用vc写的调用程序可以成功调用dll,但是vb的就不行,原因:
    用vc调用跟踪时在ReportMessage里this变量总是同一个地址,用vb调用跟踪时ReportMessage
    里在回调函数结束后this的地址值变了,然后pfnErrorCallback这个地址也不合法了,是不是dll的静态动态问题
      

  7.   

    这个是我dll的头文件,我用了stdcall了
    // B2B_API.h : interface definition
    //#if !defined(AFX_B2B_API_H__B5E847A3_1251_11D5_A662_0008C7E19073__INCLUDED_)
    #define AFX_B2B_API_H__B5E847A3_1251_11D5_A662_0008C7E19073__INCLUDED_#if _MSC_VER >= 1000
    #pragma once
    #endif // _MSC_VER >= 1000
    #ifdef B2BAPI
    #define B2B_API __declspec(dllexport)
    #else
    #define B2B_API __declspec(dllimport)
    #endif
    #define B2B_APIV __stdcallextern "C"
    {
    // Trade result type
    enum TRADERESULTTYPE
    {
    TRADERESULT_SUCCESS,
    TRADERESULT_FAIL,
    TRADERESULT_JNIERROR,
    TRADERESULT_UNKNOWN
    }; // Error message type
    enum ERRORMSGTYPE
    {
    ERRORMSG_INFO,
    ERRORMSG_WARNING,
    ERRORMSG_ERROR,
    ERRORMSG_FATAL
    }; // Define structures
    struct B2B_API B2B_SpotRate
    {
    char szID[33];
    char szRateName[7];
    long lValueDate;
    double dblBid;
    double dblAsk;
    long lBidLimit;
    long lAskLimit;
    char szLimitCcy[4];
    BOOL fTradable;
    int nTicksize;
    int nDisplayDecs;
    long lTimestamp;
    long lServerTimestamp;
    }; struct B2B_API B2B_Status
    {
    BOOL fConnected;
    BOOL fConnectedToServer; // Use this flag for connection status
    };
    struct B2B_API B2B_TradeResult
    {
    TRADERESULTTYPE enResult;
    char szReason[20];
    char szTradeID[10];
    };
    // Callback types
    typedef void (*PFNRATECALLBACK)(B2B_SpotRate*);
    typedef void (*PFNSTATUSCALLBACK)(B2B_Status*);
    typedef void (*PFNERRORCALLBACK)(ERRORMSGTYPE, char*);
    // API calls
    BOOL B2B_APIV  startJVM();
     BOOL B2B_APIV registerRateUpdate(PFNRATECALLBACK pfnRateConsumer);
     BOOL B2B_APIV registerStatusUpdate(PFNSTATUSCALLBACK pfnPropertyChangeListener);
     BOOL B2B_APIV registerErrorMessage(PFNERRORCALLBACK pfnErrorMessage);
     BOOL B2B_APIV deregisterRateUpdate();
     BOOL B2B_APIV deregisterStatusUpdate();
     BOOL B2B_APIV  tradeSpot(double dblAmount,
       double dblTradedRate,
       char cBuySell,
       char cLeftRight,
       char* szID,
       char* szRef,
       char* szCustomer,
       B2B_TradeResult* pTradeResult);}
    #endif // !defined(AFX_B2B_API_H__B5E847A3_1251_11D5_A662_0008C7E19073__INCLUDED_)
      

  8.   

    其中vb里面的调用循序是,submain调用registerErrorMessage传送REPORTMESSAGE使用的
    回调函数,我想在这个时候只要exe不退出dll里面的回调函数地址应该不会变,然后用
    按钮触发STARTJVM()设定环境,STARTJVM里面调用多个REPORTMESSAGE报告情况,顺序基本上就是这个样子了
      

  9.   

    另外补充一下,用vc写的调用程序所对应的dll函数都是使用__declspec修饰的
      

  10.   

    我想过了,你调用的函数的确是用了__stdcall,可是你的回调函数呢?这样看看吧typedef void (*PFNRATECALLBACK)(B2B_SpotRate*);
    -->
    typedef void (__stdcall *PFNRATECALLBACK)(B2B_SpotRate*);……