none
将BSTR变量赋值给CComVariant变量的疑问 RRS feed

  • 问题

  •     我写了下面一段代码:

      CComVariant varProgID; 
        varProgID.vt = VT_BSTR; 
      BSTR  bstr  = ::SysAllocString(OLESTR("esri3DAnalyst.ControlsSceneOpenDocCommand"));
       varProgID.bstrVal = bstr; 
        pFrm->m_tbr.AddItem(varProgID, -1, -1, VARIANT_FALSE, 0, esriCommandStyleIconOnly); 
        ::SysFreeString(bstr);
    



      我将varProgID.bstrVal = bstr; 改为varProgID = bstr;  
    结果在运行到varProgID = bstr这句时崩溃了,崩溃的地方是CComVariant的  
    Clear函数:
    HRESULT Clear() { return ::VariantClear(this); }

      我估计是执行operator操作符是运行Clear函数出错了。接着我又写了下面一段代码:

    CComVariant varProgID; 
        varProgID.vt = VT_BSTR; 
      BSTR  bstr  = ::SysAllocString(OLESTR("esri3DAnalyst.ControlsSceneOpenDocCommand"));
       varProgID.bstrVal = bstr; 
        pFrm->m_tbr.AddItem(varProgID, -1, -1, VARIANT_FALSE, 0, esriCommandStyleIconOnly); 
        ::SysFreeString(bstr);
    
       bstr = ::SysAllocString(OLESTR("esri3DAnalyst.ControlsSceneSceneToolbar"));
        varProgID.bstrVal = bstr;
        pFrm->m_tbr.AddItem(varProgID, -1, -1, VARIANT_FALSE, 0, esriCommandStyleIconOnly); 
        ::SysFreeString(bstr);
    

        结果在运行完上面的代码进入CComVariant的析构函数时执行Clear函数:
    HRESULT Clear() { return ::VariantClear(this); }
    又崩溃了。

      我把第二个 bstr = ::SysAllocString(OLESTR("esri3DAnalyst.ControlsSceneSceneToolbar"));
    varProgID.bstrVal = bstr;
      改为varProgID = bstr; 程序好了,运行没有问题,也没有内存泄露。

      请问varProgID.bstrVal = bstr;和varProgID = bstr;有什么区别呢?

     

     

     

     


    前无古人,后无来者
    2011年8月7日 5:43

答案


  • CComVariant varProgID;
        varProgID.vt = VT_BSTR;
      BSTR  bstr  = ::SysAllocString(OLESTR("esri3DAnalyst.ControlsSceneOpenDocCommand"));
       varProgID.bstrVal = bstr;
        pFrm->m_tbr.AddItem(varProgID, -1, -1, VARIANT_FALSE, 0, esriCommandStyleIconOnly);
        ::SysFreeString(bstr);

    Crash的原因是你指定varProgID.vt是VT_BSTR了。所以在通过operator=时,首先会FreeString,但是这时候varProgID.bstrVal 是空,所以出错了。

    后面

    CComVariant varProgID;
        varProgID.vt = VT_BSTR;
      BSTR  bstr  = ::SysAllocString(OLESTR("esri3DAnalyst.ControlsSceneOpenDocCommand"));
       varProgID.bstrVal = bstr;
        pFrm->m_tbr.AddItem(varProgID, -1, -1, VARIANT_FALSE, 0, esriCommandStyleIconOnly);
        ::SysFreeString(bstr);

       bstr = ::SysAllocString(OLESTR("esri3DAnalyst.ControlsSceneSceneToolbar"));
        varProgID.bstrVal = bstr;
        pFrm->m_tbr.AddItem(varProgID, -1, -1, VARIANT_FALSE, 0, esriCommandStyleIconOnly);
        ::SysFreeString(bstr);

    由于varProgID.bstrVal = bstr;只是浅层拷贝BSTR所以在你SysFreeString之后varProgID尝试释放varProgID.bstrVal 。但是由于指向的内存已经释放了所以又报错了。最简单的方法是不设置任何内部变量,直接使用operator=就好了。

     CComVariant varProgID; 

      BSTR  bstr  = ::SysAllocString(OLESTR("esri3DAnalyst.ControlsSceneOpenDocCommand"));
       varProgID= bstr;
        pFrm->m_tbr.AddItem(varProgID, -1, -1, VARIANT_FALSE, 0, esriCommandStyleIconOnly);
        ::SysFreeString(bstr);

       bstr = ::SysAllocString(OLESTR("esri3DAnalyst.ControlsSceneSceneToolbar"));
        varProgID= bstr;
        pFrm->m_tbr.AddItem(varProgID, -1, -1, VARIANT_FALSE, 0, esriCommandStyleIconOnly);
        ::SysFreeString(bstr);


    麻烦把正确答案设为解答。
    • 已标记为答案 Rob Pan 2011年8月12日 8:25
    2011年8月9日 9:15
    版主

全部回复

  • varProgID是CComVariant,它重载了operator=(BSTR); 在里面拷贝了bstr并赋值给bstrVal
    2011年8月8日 9:16

  • CComVariant varProgID;
        varProgID.vt = VT_BSTR;
      BSTR  bstr  = ::SysAllocString(OLESTR("esri3DAnalyst.ControlsSceneOpenDocCommand"));
       varProgID.bstrVal = bstr;
        pFrm->m_tbr.AddItem(varProgID, -1, -1, VARIANT_FALSE, 0, esriCommandStyleIconOnly);
        ::SysFreeString(bstr);

    Crash的原因是你指定varProgID.vt是VT_BSTR了。所以在通过operator=时,首先会FreeString,但是这时候varProgID.bstrVal 是空,所以出错了。

    后面

    CComVariant varProgID;
        varProgID.vt = VT_BSTR;
      BSTR  bstr  = ::SysAllocString(OLESTR("esri3DAnalyst.ControlsSceneOpenDocCommand"));
       varProgID.bstrVal = bstr;
        pFrm->m_tbr.AddItem(varProgID, -1, -1, VARIANT_FALSE, 0, esriCommandStyleIconOnly);
        ::SysFreeString(bstr);

       bstr = ::SysAllocString(OLESTR("esri3DAnalyst.ControlsSceneSceneToolbar"));
        varProgID.bstrVal = bstr;
        pFrm->m_tbr.AddItem(varProgID, -1, -1, VARIANT_FALSE, 0, esriCommandStyleIconOnly);
        ::SysFreeString(bstr);

    由于varProgID.bstrVal = bstr;只是浅层拷贝BSTR所以在你SysFreeString之后varProgID尝试释放varProgID.bstrVal 。但是由于指向的内存已经释放了所以又报错了。最简单的方法是不设置任何内部变量,直接使用operator=就好了。

     CComVariant varProgID; 

      BSTR  bstr  = ::SysAllocString(OLESTR("esri3DAnalyst.ControlsSceneOpenDocCommand"));
       varProgID= bstr;
        pFrm->m_tbr.AddItem(varProgID, -1, -1, VARIANT_FALSE, 0, esriCommandStyleIconOnly);
        ::SysFreeString(bstr);

       bstr = ::SysAllocString(OLESTR("esri3DAnalyst.ControlsSceneSceneToolbar"));
        varProgID= bstr;
        pFrm->m_tbr.AddItem(varProgID, -1, -1, VARIANT_FALSE, 0, esriCommandStyleIconOnly);
        ::SysFreeString(bstr);


    麻烦把正确答案设为解答。
    • 已标记为答案 Rob Pan 2011年8月12日 8:25
    2011年8月9日 9:15
    版主