はじめに
Windows には SAFEARRAY というデータ構造がありますが、ATL の CComSafeArray クラスはこの SAFEARRAY のラッパーです。SAFEARRAY を扱うためには、CreateSafeArray 関数など Win32 API 関数がありますが、CComSafeArray クラスを使ったほうがより簡単になります。
SAFEARRAY を使う理由ですが、C++ で書かれたモジュールと他のモジュールとのやり取りが主な目的だそうです。SAFEARRAY はモジュール境界を超えられますが、std::vector はモジュール境界を超えられないので、外部とのやり取りには利用できないそうです。
CComSafeArray の詳しい説明は下のリンクを参照してください。
MSDN Magazine: C++ - CComSafeArray による C++ でのセーフ配列プログラミングの簡素化
必要なヘッダー: atlsafe.h
CComSafeArray の構築
CComSafeArray オブジェクトを構築する方法は、以下のように多数あります。空の SAFEARRAY を構築した場合は、Add メソッドや Atach メソッドで後から要素を追加したり設定できます。
配列の長さだけ指定して、中身は後から指定することもできます。配列の添字はデフォルトでは 0 ですが、それ以外の値に変更することもできます。
- CComSafeArray();
- CComSafeArray(const SAFEARRAYBOUND& bound);
- CComSafeArray(ULONG ulCount, LONG lLBound = 0);
- CComSafeArray(const SAFEARRAYBOUND* pBound, UINT uDims = 1);
- CComSafeArray(const CComSafeArray& saSrc);
- CComSafeArray(const SAFEARRAY& saSrc);
- CComSafeArray(const SAFEARRAY* psaSrc);
CComSafeArray のメソッド
- CComSafeArray::Add Add メソッドは要素を配列の最後に追加します。次のように3種類のバージョンがあります。
- HRESULT Add(const SAFEARRAY* psaSrc);
- HRESULT Add(ULONG ulCount, const T* pT, BOOL bCopy = TRUE);
- HRESULT Add(const T& t, BOOL bCopy = TRUE);
- HRESULT Attach(const SAFEARRAY psaSrc);* SAFEARRAY* 型の psaSrc をこのオブジェクトの配列にアタッチ (psaSrc に設定されます) します。
- HRESULT CopyFrom(LPSAFEARRAY ppArray);* LPSAFEARRAY* ppArray の内容をこのオブジェクトの配列にコピーする (このオブジェクトの配列が ppArray の中身に置き換わる)。
- HRESULT CopyTo(LPSAFEARRAY ppArray);* このオブジェクトの配列のコピーを LPSAFEARRAY* ppArray に作成する。
- CComSafeArray::Create CComSafeArray オブジェクトを構築する。次の2つのバージョンがある。
- HRESULT Create(const SAFEARRAYBOUND* pBound, UINT uDims = 1);
- HRESULT Create(ULONG ulCount = 0, LONG lLBound = 0);
- HRESULT Destroy(); CComSafeArray オブジェクトを破棄する。
- LPSAFEARRAY Detach(); このオブジェクトから SAFEARRAY 配列をデタッチする (配列の割り当て解除を行う)。戻り値はデタッチした配列のポインタになる。
- T& GetAt(LONG lIndex) const; 配列要素の添字 lIndex で指定した要素を返す。
- ULONG GetCount(UINT uDim = 0) const; 配列の要素の数を返す。
- UINT GetDimensions() const; 配列の次元を返す。
- LONG GetLowerBound(UINT uDim = 0) const; uDim で指定した次元の下の境界番号 (要素の添字の最小値) を返す。
- LPSAFEARRAY GetSafeArrayPtr() throw();* この CComSafeArray オブジェクトに含まれる SAFEARRAY のポインタを返す。
- VARTYPE GetType() const; SAFEARRAY のデータ型を返す。
- VT_I1 : char
- VT_I2 : short
- VT_I4 : int
- VT_I4 : long
- VT_I8 : longlong
- VT_UI1 : byte
- VT_UI2 : ushort
- VT_UI4 : uint
- VT_UI4 : ulong
- VT_UI8 : ulonglong
- VT_R4 : float
- VT_R8 : double
- VT_DECIMAL : decimal pointer
- VT_VARIANT : variant pointer
- VT_CY : Currency data type
- LONG GetUpperBound(UINT uDim = 0) const; uDim で指定した次元の上の境界番号 (要素の添字の最大値) を返す。
- bool IsSizable() const; このオブジェクトの配列はサイズを変更可能かを返す。
- LPSAFEARRAY m_psa; この CComSafeArray オブジェクトの SAFEARRAY 構造体へのポインタを保持する公開メンバー変数。
- HRESULT MultiDimGetAt(const LONG alIndex, T& t);* 多次元配列の要素を得る。結果は t に返される。
- HRESULT MultiDimSetAt(const LONG alIndex, const T& t);* 多次元配列の要素をセットする。
- HRESULT SetAt(LONG lIndex, const T& t, BOOL bCopy = TRUE); 配列の要素をセットする。
- CComSafeArray::Resize 配列をリサイズする。次の2つのバージョンがある。
- HRESULT Resize(const SAFEARRAYBOUND* pBound);
- HRESULT Resize(ULONG ulCount, LONG lLBound = 0);
CComSafeArray の演算子
- CComSafeArray::operator [] 配列の要素を得る。これは GetAt メソッドと同じである。次の2つのバージョンがある。
- T& operator[](LONG lIndex) const;
- T& operator[](int nIndex) const;
- CComSafeArray::operator = 代入演算子。次の2つのバージョンがある。
- ATL::CComSafeArray& operator=(const ATL::CComSafeArray& saSrc);
- ATL::CComSafeArray& operator=(const SAFEARRAY* psaSrc);
サンプル
ヘッダーファイル
// stdafx.h : 標準のシステム インクルード ファイルのインクルード ファイル、または
// 参照回数が多く、かつあまり変更されない、プロジェクト専用のインクルード ファイル
// を記述します。
//
# pragma once
# include "targetver.h"
# include <stdio.h>
# include <tchar.h>
// TODO: プログラムに必要な追加ヘッダーをここで参照してください
# include <atlbase.h>
# include <atlsafe.h>
# include <atlstr.h>
CPP ファイル
// TestCcomSafeArray.cpp : アプリケーションのエントリ ポイントを定義します。
//
# include "stdafx.h"
//
// CComSafeArray のテスト
// ======================
int main()
{
// インデックスが 0 から始まる長さ 100 の配列。中身は 0 で初期化される。
CComSafeArray ai(100);
int i;
// GetAt, SetAt メソッド
printf_s("%d\n", ai.GetAt(0));
ai.SetAt(0, 50);
printf_s("%d\n", ai.GetAt(0));
// 境界の外に書き込み
// DEBUG モードでは Assert が起こる。RELEASE モードでは何もしない。
ai.SetAt(100, 100);
// 配列の境界は指定可能
CComSafeArray<short> as(10, 1); // インデックスが 1 から始まる長さ 10 の配列。
printf_s("LB = %d, UB = %d\n", as.GetLowerBound(), as.GetUpperBound());
// Add メソッド
as.Add(1);
as.Add(2);
printf_s("LB = %d, UB = %d\n", as.GetLowerBound(), as.GetUpperBound());
printf_s("%d, %d\n", as.GetAt(11), as.GetAt(12));
// 中身の SAFEARRAY を参照
LPSAFEARRAY *sa = ai.GetSafeArrayPtr();
// 終わり
getchar();
return 0;
}