我的一个接口的方法除了有各个返回值外,
[id(2), helpstring("method GetNext")] HRESULT GetNext([in] VARIANT strIP, [in] VARIANT strOid, [in] VARIANT strPublic, [out] VARIANT* pROid,[out,retval] VARIANT* pValue);
其中out] VARIANT* pROid,[out,retval] VARIANT* pValue分别是参数返回值、结果返回值。
我的实现代码如下:
1)客户端部分访问代码如下:
{
         。
DISPPARAMS dispparms;
memset(&dispparms,0,sizeof(DISPPARAMS));
dispparms.cArgs=4;
VARIANTARG* pArg= new VARIANTARG[4];
dispparms.rgvarg=pArg; memset( pArg,0,sizeof(VARIANT)*4 ); CComBSTR bstrtemp1;
bstrtemp1="public";
dispparms.rgvarg[1].vt=VT_BSTR;
dispparms.rgvarg[1].bstrVal=BSTR( bstrtemp1 ); CComBSTR bstrtemp2;
bstrtemp2="1";
dispparms.rgvarg[2].vt=VT_BSTR;
dispparms.rgvarg[2].bstrVal=BSTR( bstrtemp2 ); CComBSTR bstrtemp3;
bstrtemp3="202.206.219.243";
dispparms.rgvarg[3].vt=VT_BSTR;
dispparms.rgvarg[3].bstrVal=BSTR( bstrtemp3 );

VARIANT vtResult;
VariantInit( &vtResult );
if( pDispatch->Invoke(dispid,IID_NULL,LOCALE_SYSTEM_DEFAULT,DISPATCH_METHOD,&dispparms,&vtResult,0,NULL)!=S_OK )
{
MessageBox("Invoke Error");
return;
}
CString strResult;
strResult=vtResult.bstrVal;
// MessageBox( strResult );
if(vtResult.vt==VT_BSTR)
{
strResult=vtResult.bstrVal;
MessageBox( strResult );
//bstrtemp=strResult;
} CString strROid;
strROid=dispparms.rgvarg[0].bstrVal; MessageBox( strROid );
}
2)服务器段的部分代码如下:
STDMETHODIMP CSnmp::GetNext(VARIANT strIP, VARIANT strOid, VARIANT strPublic, VARIANT *pROid, VARIANT *pValue)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
CString cstrip;
CString cstroid;
CString cstrcomm;
CString cstrRoid; cstrip=strIP.bstrVal;
cstroid=strOid.bstrVal;
cstrcomm=strPublic.bstrVal
SnmpMgr snmpmgr;
char strValue[65530];
char strROid[65530];
char* pstr=snmpmgr.GetRequestNext(cstrip,cstroid,cstrcomm,cstrRoid); if( pstr==NULL )
return S_FALSE;
strcpy(strValue,pstr );
strcpy(strROid,cstrRoid); CComBSTR bstr(strValue);
CComBSTR bstrR(strROid); VariantInit( pROid );
pROid->vt=VT_BSTR;
pROid->bstrVal= bstrR.m_str;

pValue->vt=VT_BSTR;
pValue->bstrVal=bstr.m_str; return S_OK;
}但是执行的结果是结果值正确,也就是[out,retval] VARIANT* pValue值正确。
而返回值为空,也就是[out] VARIANT* pROid为空。
我用断点的调试看,pROid的值确实是我想要的正确答案啊。难道是返回时,指针有问题。哪位高手解答!!!!!!!!!

解决方案 »

  1.   

    不好意思,我没编过这方面的程序,不知道应该怎么做,不过看得出楼主的程序有几个错误。你再传参数进去之前不初始化dispparms.rgvarg[0],在GetNext中才初始化它,这应该是错的。
    GetNext的pROid可能并不是dispparms.rgvarg[0],因为楼主借助MFC的Invoke的辅助函数,通过映射才调用GetNext,之间已经被Invoke的辅助函数倒过一次手,可能并不是dispparms.rgvarg[0]。
    楼主既然定了pROid为VARIANT*,那就应该调用前VARIANT var;,初始化dispparms.rgvarg[0]为&var,而不是直接传个0过去。上面所说不敢确认,我对这方面不熟。不过楼主的
    pROid->bstrVal= bstrR.m_str;和
    pValue->bstrVal=bstr.m_str;
    应该会导致内存访问违规,因为bstrR和bstr都是CComBSTR的局部变量,它们在离开GetNext后,将调用~CComBSTR(),里面将释放bsrtR.m_str和bstr.m_str,这样当在调用端使用返回值时,将指向错误的内存,不过可能不报错。因为楼主大概只是对那段内存(vtResult)读操作,所以不报错,但是在vtResult的析构中应该会试图释放这块早已释放的内存,到时将发生内存操作错误。
    所以楼主的那两句话应改成
    pROid->bstrVal = bstrR.Detach();和
    pValue->bstrVal = bstr.Detach();
      

  2.   

    谢谢 lop5712(LOP) 的回答,dispparms.rgvarg[0]是一个非输入数,我想不需要初始化吧,后面一些讲的很有道理,不过我都按你的所有要点改了,没有解决问题。UP!!!!!!!!!!!!!!!!!!!!!!!
    1!!!!!!!!!!!!!!!!!!!!!!!
      

  3.   

    1. 代码中没看到你对pROid操作 ?2. 注意你的 ->vt = xxx; 
      

  4.   

    我回去看了一下自动化方面的书,楼主的错误是因为楼主使用MFC进行实现IDispatch(即CCmdTarget),而在CCmdTarget中,楼主传进去的参数dispparms.rgvarg在调用CSnmp::GetNext以前会先拷贝到栈上,即楼主在CSnmp::GetNext中以为的pROid实际指向由CCmdTarget创建的一小块栈上,并不是客户端的内存,所以失败。正确使用方法是所有的输出参数都应指定VT_BYREF,并在VARIANT::byref(一个void*,可能名字有误,记不到了)填写相应的指针,如下:在CSnmp的Dispatch的映射宏中,指定GetNext的参数为
    VTS_VARIANT VTS_VARIANT VTS_VARIANT VTS_PVARIANT
    即一定指明VTS_PVARIANT在客户端
    VARIANT roid;
    dispparms.rgvarg[0].vt = VT_BYREF | VT_VARIANT;
    dispparms.rgvarg[0].byref = &roid;
    Ivoke后,roid中即装着输出结果如上即可,我测试成功,但前提条件是自动化服务器一定是进程内服务器,因为&roid在另一个进程中是无意义的。另外就是原来没注意到,楼主的vtResult是VARIANT,不是COleVariant,所以不会自动释放vtResult.bstrVal,楼主必须显示释放,如:
    ::SysFreeString( vtResult.bstrVal );或::VariantClear( &vtResult );
    同理,前述的roid也需要显示释放,调用::VariantClear( &roid );
      

  5.   

    非常感谢 lop5712(LOP) 的回答,我用你的做法弄出来了,但是我是运用
             UCHAR s[200];
    dispparms.rgvarg[0].vt = VT_BYREF|VT_UI1;
    dispparms.rgvarg[0].pbVal = s;
    也就是UCHAR FAR*类型。
    你的VARIANT roid;
    dispparms.rgvarg[0].vt = VT_BYREF | VT_VARIANT;
    dispparms.rgvarg[0].byref = &roid;我有点不理解?在服务器端映射的roid究竟他的结构中是什么类型了,是BSTR吗?主用是不会应用,不过看来应用BSTR这种类型时一定要小心。这好像是一个未分配的指针。对了楼上的说我在服务端用了MFC?哦,我没有使用MFC的消息流,CSnmp这个类是我自己封装的独立类。希望大家再帮我讨论一下为什么不能,和怎样传回BSTR这种类型的值。
      

  6.   

    Roid不代表任何类型,只是一个未初始化的VARIANT,因为它是一个类型为VARIANT*的输出参数,意义就是维护一块缓冲区,将指针传进服务器,由服务器操作这块缓冲区。楼主不就是在GetNext中如下操作这块缓冲区,并初始化了这个本来没有初始化化的VARIANT
    VariantInit( pROid );
    pROid->vt=VT_BSTR;
    pROid->bstrVal=bstrR.m_str;我不是说消息映射宏,是Dispatch映射宏。楼主的服务器肯定是MFC编的,不然就没有
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    而Dispatch映射宏是用来帮助程序员简单编写IDispatch接口的Ivoke用的,楼主的程序是双接口的(同时支持IDispatch和ISnap),那么楼主难道自己实现了IDispatch::Ivoke这个函数?
    楼主的程序中是否存在BEGIN_DISPATCH_MAP宏和END_DISPATCH_MAP宏,假如存在,那么楼主就是借助MFC提供的实现IDispatch::Ivoke的机制,因此,楼主的所有方法和属性都必须在上述的两个宏中有一对应的Dispatch映射宏,类似下面的
    DISP_FUNCTION( CSnmp, "GetNext", GetNext, VT_VARIANT, VTS_VARIANT VTS_VARIANT VTS_PVARIANT )
    楼主如果使用向导添加方法,那么向导会自动在BEGIN_DISPATCH_MAP和END_DISPATCH_MAP之间添加类似上面的映射宏,楼主查看下源代码,看是否存在映射宏(如果是VC6,它们可能是灰色的,因为是由ClassWizard创建)。
    如果楼主的代码中有上述的东西,那么楼主失败的原因我已经在上一个帖子中说明了,不再重复,至于为什么楼主使用VT_BYREF | VT_BSTR才能获得成功,很有可能楼主在映射宏写成如下
    DISP_FUNCTION( CSnap, "GetNext", GetNext, VT_VARIANT, VTS_VARIANT VTS_VARIANT VTS_PBSTR )
    // 注:也可VTS_PWBSTR,其代表WCHAR*,而VTS_PBSTR代表BYTE*另外的,上次我说的有点错误,应写成
    VARIANT roid;
    dispparms.rgvarg[0].vt = VT_BYREF | VT_VARIANT;
    dispparms.rgvarg[0].pvarVal = &roid;  // 不是dispparms.rgvarg[0].byref
    因为byref是个void*,而pvarVal是个VARIANT*,在此这种情况是没有什么影响的(但并不总是如此),因为pvarVal和byref是同一个联合的成员,所以本质一样,不过意义不一样,应改成如上。