最近遇到使用SAFEARRAY比较多,因为是三维图形方面,用到的SAFEARRAY一般都是一维的数组,元素个数为1(表示参数曲线),2(表示参数曲面),3(表示三维点).于是写了一个针对这方面的类.
  我想值得讨论是地方有两个, 一是SAFEARRAY的使用,一就是关于通用类编写的一些准则(比如说实现正规函数,转型,以及错误处理等等),希望大家能够批评指教.#pragma once
#include <assert.h>
#include <oleauto.h>
#include <math.h>const double E_PRECISION = 0.0001;template<int dimension>
class CDbSafeArray
{
public:
//constructor
explicit CDbSafeArray(double t);
CDbSafeArray(double u,double v);
CDbSafeArray(double x,double y,double z);
CDbSafeArray(const SAFEARRAY* psa); //copy constructor
CDbSafeArray(const CDbSafeArray& rhs); ~CDbSafeArray();public:
//operator override
SAFEARRAY** operator&(); CDbSafeArray& operator = (const CDbSafeArray& rhs); bool Equal(double dbleft,double dbright); bool operator == ( const CDbSafeArray& rhs); bool operator != ( const CDbSafeArray& rhs);public:
//data access
//for parameterized curve  dimension = 1
HRESULT get_T(double& T);
HRESULT set_T(double T); //for parameterized surface dimension = 2
HRESULT get_U(double& U);
HRESULT set_U(double U);
HRESULT get_V(double& V);
HRESULT set_V(double V); //for 3d point dimension = 3
HRESULT get_X(double& X);
HRESULT set_X(double X);
HRESULT get_Y(double& Y);
HRESULT set_Y(double Y);
HRESULT get_Z(double& Z);
HRESULT set_Z(double Z); //
HRESULT setdata(double T);
HRESULT getdata(double& T); HRESULT setdata(double U,double V);
HRESULT getdata(double& U,double& V); HRESULT setdata(double X,double Y, double Z);
HRESULT getdata(double& X,double& Y, double& Z);public:
//safearray
SAFEARRAY* m_psa;private:
//the length of the array(only 1,2,3 allowed)
int m_idimension;};

解决方案 »

  1.   

    template<int dimension>
    CDbSafeArray<dimension>::CDbSafeArray(double t):m_psa(NULL),m_idimension(dimension)
    {
    assert(dimension == 1);
    try
    {
    if(dimension != 1) throw;
    //create
    m_psa = ::SafeArrayCreateVector(VT_R8,0,1);
    if(m_psa == NULL)
    throw;
    //access data
    double* pd = NULL;
    HRESULT hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))
    throw;
    pd[0] = t;
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr))
    throw;
    m_idimension = dimension;
    }
    catch(...)
    {
    if(m_psa != NULL)
    {
    ::SafeArrayDestroy(m_psa);
    m_psa = NULL;
    }
    }
    }template<int dimension>
    CDbSafeArray<dimension>::CDbSafeArray(double u,double v):m_psa(NULL),m_idimension(dimension)
    {
    assert(dimension == 2);
    try
    {
    if(dimension != 2) throw;
    //create
    m_psa = ::SafeArrayCreateVector(VT_R8,0,2);
    if(m_psa == NULL)
    throw; //access data
    double* pd = NULL;
    HRESULT hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))
    throw;
    pd[0] = u;
    pd[1] = v;
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr))
    throw;
    m_idimension = dimension;
    }
    catch(...)
    {
    if(m_psa != NULL)
    {
    ::SafeArrayDestroy(m_psa);
    m_psa = NULL;
    }
    }
    }
    template<int dimension>
    CDbSafeArray<dimension>::CDbSafeArray(double x,double y,double z):m_psa(NULL),m_idimension(dimension)
    {
    assert(dimension == 3);
    try
    {
    if(dimension != 3) throw;
    //create
    m_psa = ::SafeArrayCreateVector(VT_R8,0,3);
    if(m_psa == NULL)
    throw;
    //access data
    double* pd = NULL;
    HRESULT hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))
    throw;
    pd[0] = x;
    pd[1] = y;
    pd[2] = z;
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr))
    throw;
    m_idimension = dimension;
    }
    catch(...)
    {
    if(m_psa != NULL)
    {
    ::SafeArrayDestroy(m_psa);
    m_psa = NULL;
    }
    }
    }
    template<int dimension>
    CDbSafeArray<dimension>::CDbSafeArray(const SAFEARRAY* psa):m_psa(NULL)
    {
    //psa must created
    assert(psa != NULL);
    try
    {
    if(psa == NULL)
    throw;
    LONG lUpDim;
    HRESULT hr = ::SafeArrayGetUBound(psa,1,&lUpDim);
    if(FAILED(hr)) throw;
    if(dimension != ++lUpDim)
    throw;
    m_psa = psa;
    m_idimension = dimension; }
    catch (_com_error) 
    {
    }
    catch(...)
    {
    }}template<int dimension>
    CDbSafeArray<dimension>::CDbSafeArray(const CDbSafeArray& rhs): m_psa(NULL)
    {
    operator=(rhs);
    }
    template<int dimension>
    CDbSafeArray<dimension>::~CDbSafeArray()
    {
    if(m_psa != NULL)
    {
    ::SafeArrayDestroy(m_psa);
    m_psa = NULL;
    }
    }template<int dimension>
    SAFEARRAY** CDbSafeArray<dimension>::operator&()
    {
    // Directly accessing the address of the internal SAFEARRAY is assumed
    // to only be done with the intent to use as an out argument in a call
    // and should therefore only be done when it is NULL or leaking will occur.
    // If this is not the intent, access the m_psa member directly.
    assert(!m_psa);
    try
    {
    if(m_psa == NULL)
    throw;
    return &m_psa; }
    catch (...)
    {
    }
    }
    template<int dimension>
    CDbSafeArray<dimension>& CDbSafeArray<dimension>::operator = (const CDbSafeArray& rhs)
    {
    assert(rhs.m_psa);
    try
    {
    if(rhs.m_psa == NULL)
    throw;
    if(dimension != rhs.m_idimension)
    throw;
    if (&m_psa == &rhs.m_psa)
    throw; HRESULT hr = S_OK;
    if (rhs.m_psa)
    {
    //it will create a safearray for m_psa
    hr = SafeArrayCopy(rhs.m_psa, &m_psa);
    }
    assert(SUCCEEDED(hr));
    if(FAILED(hr)) 
    throw;
    m_idimension = dimension;
    }
    catch (...) 
    {
    } return *this;
    }template<int dimension>
    bool CDbSafeArray<dimension>::Equal(double dbleft,double dbright)
    {
    if(fabs(dbleft - dbright)<E_PRECISION)
    return true;
    else 
    return false;}
    template<int dimension>
    bool CDbSafeArray<dimension>::operator == ( const CDbSafeArray& rhs)
    {
    HRESULT hr = S_OK;
    assert(rhs.m_psa);
    try
    {
    if(rhs.m_psa == NULL)
    throw;
    if(m_idimension!= rhs.m_idimension)
    throw;
    if (&m_psa == &rhs.m_psa)
    return true; if (rhs.m_psa)
    {
    double *pd1 = NULL;
    double *pd2 = NULL;
    hr = ::SafeArrayAccessData(m_psa,(void**)&pd1);
    if(FAILED(hr)) throw;
    hr = ::SafeArrayAccessData(rhs.m_psa,(void**)&pd2);
    if(FAILED(hr)) throw;
    if(m_idimension == 1)
    {
    if(Equal(pd1[0],pd2[0]))
    return true;
    else 
    return false; }
    else if(m_idimension == 2)
    {
    if(Equal(pd1[0],pd2[0]) && Equal(pd1[1],pd2[1]))
    return true;
    else 
    return false;
    }
    else if(m_idimension == 3)
    {
    if(Equal(pd1[0],pd2[0]) && Equal(pd1[1],pd2[1]) && Equal(pd1[2],pd2[2]))
    return true;
    else 
    return false;
    }
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr)) throw;
    hr = ::SafeArrayUnaccessData(rhs.m_psa);
    if(FAILED(hr)) throw;
    } }
    catch (...) 
    {
    }
    }template<int dimension>
    bool CDbSafeArray<dimension>::operator != ( const CDbSafeArray& rhs)
    {
    if(*this == rhs)
    return false;
    else 
    return true;}
      

  2.   

    template<int dimension>
    HRESULT CDbSafeArray<dimension>::get_T(double& T)
    {
    HRESULT hr = S_OK;
    assert(dimension == 1);
    if(dimension != 1) 
    return E_FAIL;
    //access data
    double* pd = NULL;
    hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))  return hr;
    T = pd[0];
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr)) return hr;
    return hr;
    }
    template<int dimension>
    HRESULT CDbSafeArray<dimension>::set_T(double T)
    {
    HRESULT hr = S_OK;
    assert(dimension == 1);
    if(dimension != 1) 
    return E_FAIL;
    //access data
    double* pd = NULL;
    hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))  return hr;
    pd[0] = T;
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr)) return hr;
    return hr;
    }template<int dimension>
    HRESULT CDbSafeArray<dimension>::get_U(double& U)
    {
    HRESULT hr = S_OK;
    assert(dimension == 2);
    if(dimension != 2) 
    return E_FAIL;
    //access data
    double* pd = NULL;
    hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))  return hr;
    U = pd[0];
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr)) return hr;
    return hr;
    }
    template<int dimension>
    HRESULT CDbSafeArray<dimension>::set_U(double U)
    {
    HRESULT hr = S_OK;
    assert(dimension == 2);
    if(dimension != 2) 
    return E_FAIL;
    //access data
    double* pd = NULL;
    hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))  return hr;
    pd[0] = U;
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr)) return hr;
    return hr;
    }
    template<int dimension>
    HRESULT CDbSafeArray<dimension>::get_V(double& V)
    {
    HRESULT hr = S_OK;
    assert(dimension == 2);
    if(dimension != 2) 
    return E_FAIL;
    //access data
    double* pd = NULL;
    hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))  return hr;
    V = pd[1];
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr)) return hr;
    return hr;
    }
    template<int dimension>
    HRESULT CDbSafeArray<dimension>::set_V(double V)
    {
    HRESULT hr = S_OK;
    assert(dimension == 2);
    if(dimension != 2) 
    return E_FAIL;
    //access data
    double* pd = NULL;
    hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))  return hr;
    pd[1] = V;
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr)) return hr;
    return hr;
    }template<int dimension>
    HRESULT CDbSafeArray<dimension>::get_X(double& X)
    {
    HRESULT hr = S_OK;
    assert(dimension == 3);
    if(dimension != 3) 
    return E_FAIL;
    //access data
    double* pd = NULL;
    hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))  return hr;
    X = pd[0];
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr)) return hr;
    return hr;
    }
    template<int dimension>
    HRESULT CDbSafeArray<dimension>::set_X(double X)
    {
    HRESULT hr = S_OK;
    assert(dimension == 3);
    if(dimension != 3) 
    return E_FAIL;
    //access data
    double* pd = NULL;
    hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))  return hr;
    pd[0] = X;
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr)) return hr;
    return hr;
    }
    template<int dimension>
    HRESULT CDbSafeArray<dimension>::get_Y(double& Y)
    {
    HRESULT hr = S_OK;
    assert(dimension == 3);
    if(dimension != 3) 
    return E_FAIL;
    //access data
    double* pd = NULL;
    hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))  return hr;
    Y = pd[1];
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr)) return hr;
    return hr;
    }
    template<int dimension>
    HRESULT CDbSafeArray<dimension>::set_Y(double Y)
    {
    HRESULT hr = S_OK;
    assert(dimension == 3);
    if(dimension != 3) 
    return E_FAIL;
    //access data
    double* pd = NULL;
    hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))  return hr;
    pd[1] = Y;
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr)) return hr;
    return hr;
    }
    template<int dimension>
    HRESULT CDbSafeArray<dimension>::get_Z(double& Z)
    {
    HRESULT hr = S_OK;
    assert(dimension == 3);
    if(dimension != 3) 
    return E_FAIL;
    //access data
    double* pd = NULL;
    hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))  return hr;
    Z = pd[2];
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr)) return hr;
    return hr;
    }
    template<int dimension>
    HRESULT CDbSafeArray<dimension>::set_Z(double Z)
    {
    HRESULT hr = S_OK;
    assert(dimension == 3);
    if(dimension != 3) 
    return E_FAIL;
    //access data
    double* pd = NULL;
    hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))  return hr;
    pd[2] = Z;
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr)) return hr;
    return hr;
    }template<int dimension>
    HRESULT setdata(double T)
    {
    return set_T(T);
    }
    template<int dimension>
    HRESULT getdata(double& T)
    {
    return get_T(T);
    }template<int dimension>
    HRESULT setdata(double U,double V)
    {
    HRESULT hr = S_OK;
    assert(dimension == 2);
    if(dimension != 2) 
    return E_FAIL;
    //access data
    double* pd = NULL;
    hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))  return hr;
    pd[0]  = U;
    pd[1] = V;
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr)) return hr;
    return hr;
    }
    template<int dimension>
    HRESULT getdata(double& U,double& V)
    {
    HRESULT hr = S_OK;
    assert(dimension == 2);
    if(dimension != 2) 
    return E_FAIL;
    //access data
    double* pd = NULL;
    hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))  return hr;
    U = pd[0];
    V = pd[1];
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr)) return hr;
    return hr;
    }
    template<int dimension>
    HRESULT setdata(double X,double Y, double Z)
    {
    HRESULT hr = S_OK;
    assert(dimension == 3);
    if(dimension != 3) 
    return E_FAIL;
    //access data
    double* pd = NULL;
    hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))  return hr;
    pd[0] = X;
    pd[1] = Y;
    pd[2] = Z;
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr)) return hr;
    return hr;
    }
    template<int dimension>
    HRESULT getdata(double& X,double& Y, double& Z)
    {
    HRESULT hr = S_OK;
    assert(dimension == 3);
    if(dimension != 3) 
    return E_FAIL;
    //access data
    double* pd = NULL;
    hr = ::SafeArrayAccessData(m_psa,(void**)&pd);
    if(FAILED(hr))  return hr;
    X = pd[0];
    Y = pd[1];
    Z = pd[2];
    hr = ::SafeArrayUnaccessData(m_psa);
    if(FAILED(hr)) return hr;
    return hr;
    }
      

  3.   

    -----------------------使用-------------------------------------------------
    CDbSafeArray<3> sa3(0.1,2.4,4.5);
    CDbSafeArray<3> sa4(0.1,2.4,4.5);
    CDbSafeArray<3> sa5(0.1,2.4,4.1); CDbSafeArray<3> sa6(sa5); if(sa4 != sa5)
    AfxMessageBox(_T("sa4 != sa5"));
    if(sa6 == sa5)
    AfxMessageBox(_T("sa6 = sa5"));
    if(sa5 == sa3)
    AfxMessageBox(_T("sa3 = sa5"));
      

  4.   

    不错,鼎不过呢,MS都有现成的MFC封装类,何必这么辛苦呢
      

  5.   

    呵呵,看来有共同的爱好,喜欢写些基础的类.
    我想这是在更深层次上学习模板的好办法.我也做了个CSafeArray,比起CComSafeArray,它提供了对自定义类型数组的支持,交流一下.
    http://IUnknown.6to23.com/
      

  6.   

    COleSafeArray
    The COleSafeArray class is used for working with arrays of arbitrary types and dimensions. COleSafeArray provides implementations of the COM SAFEARRAY member functions, as well as a set of member functions specifically designed for one-dimensional arrays of bytes. COleSafeArray derives from the COM VARIANT structure.