永続化と初期化の最適化
コントロールの永続化と初期化は、既定では DoPropExchange メンバー関数によって処理されます。 一般的なコントロールの場合、この関数には、PX_Color や PX_Font などの PX_ 関数の呼び出しが含まれています。これらの関数は、プロパティごとに一度ずつ呼び出されます。
この最適化の利点は、1 つの DoPropExchange を実装すると、初期化、バイナリ形式の永続化、および一部のコンテナーで使用される "プロパティ バッグ" と呼ばれる形式の永続化に使用できることです。 つまり、この関数によって、各種のプロパティおよびその既定値に関するすべての情報が 1 か所で提供されます。
ただし、効率は低下します。 PX_ 関数の柔軟性は、多階層の実装によって実現しているため、柔軟性は低いがより直接的なほかの方法に比べると、本質的に効率が劣ります。 さらに、PX_ 関数に既定値を渡すコントロールでは、既定値を使う必要がない場合でも常に既定値を渡すことになります。 既定値をアンビエント プロパティから取得する場合などは、既定値を作成する作業が複雑になりますが、渡した既定値は結局は使用されないため、作成に費やす作業は無駄になります。
コントロールの Serialize 関数をオーバーライドすると、コントロールのバイナリ永続化のパフォーマンスを改善できます。 このメンバー関数の既定の実装では、DoPropExchange 関数が呼び出されます。 オーバーライドすることによって、バイナリ永続化のためのより直接的な実装を提供できます。 例として、次の DoPropExchange 関数について考えてみます。
void CMyAxOptCtrl::DoPropExchange(CPropExchange* pPX)
{
ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
COleControl::DoPropExchange(pPX);
PX_Bool(pPX, _T("BoolProp"), m_BoolProp, TRUE);
PX_Short(pPX, _T("ShortProp"), m_ShortProp, 0);
PX_Color(pPX, _T("ColorProp"), m_ColorProp, RGB(0xFF,0x00,0x00));
PX_String(pPX, _T("StringProp"), m_StringProp, _T(""));
}
このコントロールのバイナリ永続化のパフォーマンスを改善するには、Serialize 関数を次のようにオーバーライドします。
void CMyAxOptCtrl::Serialize(CArchive& ar)
{
SerializeVersion(ar, MAKELONG(_wVerMinor, _wVerMajor));
SerializeExtent(ar);
SerializeStockProps(ar);
if (ar.IsLoading())
{
ar >> m_BoolProp;
ar >> m_ShortProp;
ar >> m_ColorProp;
ar >> m_StringProp;
}
else
{
ar << m_BoolProp;
ar << m_ShortProp;
ar << m_ColorProp;
ar << m_StringProp;
}
}
ローカル変数 dwVersion を使うと、読み込みまたは保存が行われた永続的な状態のコントロールを検出できます。 CPropExchange::GetVersion を呼び出す代わりにこの変数を使用できます。
BOOL プロパティの永続化形式の領域を少しでも節約し、PX_Bool によって生成される形式との互換性を維持するには、次のように、BOOL プロパティを BYTE 型として格納します。
if (ar.IsLoading())
{
BYTE bTmp;
ar >> bTmp;
m_BoolProp = (BOOL)bTmp;
// other properties...
}
else
{
ar << (BYTE)m_BoolProp;
// other properties...
}
読み込み状態の場合、m_boolProp は BYTE 型の参照にキャストされず、一時変数が使用され、その値が代入されます。 キャストを使った場合は、m_boolProp の 1 バイトだけが変更され、残りのバイトは初期化されません。
同じコントロールの初期化を最適化するには、COleControl::OnResetState を次のようにオーバーライドします。
void CMyAxOptCtrl::OnResetState()
{
ResetVersion(MAKELONG(_wVerMinor, _wVerMajor));
ResetStockProps();
m_BoolProp = TRUE;
m_ShortProp = 0;
m_ColorProp = RGB(0xFF,0x00,0x00);
m_StringProp.Empty();
}
Serialize と OnResetState をオーバーライドしましたが、DoPropExchange 関数はそのままにしておく必要があります。これは、プロパティバッグ形式の永続化で使用するためです。 これら 3 つの関数については、コンテナーで使用される永続化の形式に関係なく、コントロールが一貫してプロパティを管理できるようにしておく必要があります。