Visual Studio 2017 Visual C++ : COM 文字列 BSTR と CComBSTR

#はじめに
COM / OLE では文字列型として BSTR という型が使用されます。これは次のように定義されます。

>typedef OLECHAR* BSTR;

*OLECHAR* とはワイド文字のことなので、*BSTR* はワイド文字のポインタ (wchar_t*) ということになります。

BSTR には ATL のクラス CComBSTR が薄いラッパーになっているので、BSTR を扱う場合は、BSTR を直接扱うより CComBSTR を扱ったほうが便利です。

参照 [MSDN CComBSTR クラス](https://msdn.microsoft.com/ja-jp/library/zh7x9w3f.aspx)

必要なヘッダー： atlstr.h

#BSTR の初期化
BSTR に文字列を割り当てるには、SysAllocString API 関数を使用します。BSTR は wchar_t* と同じなので、不要になった場合は文字列のメモリ領域を解放する必要があります。解放には SysFreeString API 関数を使用します。

```C++
// AllocSysString で BSTR を初期化
BSTR str = SysAllocString(L"Hello");
wprintf_s(L"%s\n", str);  // BSTR を表示
SysFreeString(str);  // 解放
```

API 関数の代わりに CComBSTR クラスを使う方法もあります。

```C++
// CComBSTR で BSTR を初期化
BSTR bstr1 = CComBSTR(L"Hello");
wprintf_s(L"%s\n", bstr1);  // BSTR を表示
```

逆に BSTR から CComBSTR を作成することもできます。

```C++
// BSTR から CComBSTR を作成
CComBSTR cstr1(bstr1);
wprintf_s(L"%s\n", cstr1);  // CComBSTR は自動的に BSTR に変換されて表示される。(警告はでるが)
```

##CComBSTR のコンストラクタ
CComBSTR のコンストラクタには、次のように多数のバージョンがあります。

- CComBSTR() throw();
- CComBSTR(const CComBSTR& src);
- CComBSTR(REFGUID guid);
- CComBSTR(int nSize);
- CComBSTR(int nSize, LPCOLESTR sz);
- CComBSTR(int nSize, LPCSTR sz);
- CComBSTR(LPCOLESTR pSrc);
- CComBSTR(LPCSTR pSrc);
- CComBSTR(CComBSTR&& src);

#生の C スタイル文字列を取得
生の C スタイル文字列を取得することもできます。この文字列は常にワイド文字列です。

```C++
CComBSTR cstr1;
// ... cstr1 の内容を決める処理。

// C スタイル文字列を取得
WCHAR cstyle[100];
swprintf_s(cstyle, L"%s", cstr1);
wprintf_s(L"C style: %s\n", cstyle);
```

#メソッドの使用
CComBSTR には多くのメソッドが用意されているので、文字列処理が容易になります。

```C++
// 長さを取得:  cstr1 は CComBSTR オブジェクト
wprintf_s(L"Length: %d\n", cstr1.Length());

// 結合
cstr1.AppendBSTR(bstr);
wprintf_s(L"Append: %s\n", cstr1);

// コピー
BSTR bstr2 = cstr1.Copy();
wprintf_s(L"Copy: %s\n", bstr2);
```

##CComBSTR メソッドの一覧
- **CComBSTR::Append**　このオブジェクトの文字列に別の文字列を追加する。次のように多数のバージョンがある。
 - HRESULT Append(const CComBSTR& bstrSrc) throw();
 - HRESULT Append(wchar_t ch) throw();
 - HRESULT Append(char ch) throw();
 - HRESULT Append(LPCOLESTR lpsz) throw();
 - HRESULT Append(LPCSTR lpsz) throw();
 - HRESULT Append(LPCOLESTR lpsz, int nLen) throw();
- **HRESULT CComBSTR::AppendBSTR(BSTR p) throw**　このオブジェクトの文字列に BSTR 型文字列を追加する。
- **HRESULT CComBSTR::AppendBytes(const char* lpsz, int nLen) throw()**　nLen で指定された長さのバイトデータをそのまま追加する。
- **HRESULT CComBSTR::ArrayToBSTR(const SAFEARRAY* pSrc) throw()**　SAFEARRAY の各要素の先頭の文字から BSTR を作成して、このオブジェクトの文字列とする。
- **HRESULT CComBSTR::AssignBSTR(const BSTR bstrSrc) throw()**　bstrSrc をこのオブジェクトの文字列にする。
- **void CComBSTR::Attach(BSTR src) throw()**　src をこのオブジェクトにアタッチする (このオブジェクトの文字列にする)。
- **HRESULT CComBSTR::BSTRToArray(LPSAFEARRAY* ppArray) throw()**　このオブジェクトの文字列から SAFEARRAY 型配列を作る。配列の各要素はもとの文字列の文字である。
- **unsigned int CComBSTR::ByteLength() const throw()**　この文字列のバイト長を返す。
- **BSTR CComBSTR::Copy() throw()**　このオブジェクトの文字列をコピーする。戻り値は BSTR でコピーした文字列になる。
- **CComBSTR::CopyTo**　パラメータにこのオブジェクトの文字列をコピーする。次の２バージョンがある。
 - HRESULT CopyTo(BSTR* pbstr) throw();
 - HRESULT CopyTo(VARIANT* pvarDest) throw();
- **BSTR CComBSTR::Detach() throw()**　このオブジェクトの文字列をデタッチする (このオブジェクトの文字列を NULL にする)。
- **void CComBSTR::Empty() throw()**　このオブジェクトの文字列を解放する。
- **unsigned int CComBSTR::Length() const throw()**　このオブジェクトの文字列の文字数を返す。
- **CComBSTR::LoadString**　nID で指定された文字列リソースをこのオブジェクトの文字列にロードする。次の2つバージョンがある。
 - bool LoadString(HINSTANCE hInst, UINT nID) throw();
 - bool LoadString(UINT nID) throw();
- **BSTR CComBSTR::m_str;**　m_str はメソッドでなく公開メンバー変数で、BSTR 文字列自身である。
- **HRESULT CComBSTR::ReadFromStream(IStream* pStream) throw()**　pStream で指定されたストリームからこのオブジェクトの文字列に読み込む。
- **HRESULT CComBSTR::ToLower() throw()**　このオブジェクトの文字列の大文字をすべて小文字にする。
- **HRESULT CComBSTR::ToUpper() throw()**　このオブジェクトの文字列の大文字をすべて小文字にする。
- **HRESULT CComBSTR::WriteToStream(IStream* pStream) throw()**　pStream で指定されたストリームにこのオブジェクトの文字列に書き込む。

#演算子
CComBSTR クラスには多数の演算子が定義されています。これにより、生の BSTR 変数どうしの比較処理などより、ずっと簡単に処理ができます。

```C++
// 比較
if (cstr1 == bstr1)
{
	wprintf_s(L"True\n");
}
else
{
	wprintf_s(L"False\n");
}
```

##CComBSTR の演算子一覧
- CComBSTR::operator BSTR
- CComBSTR::operator !
- CComBSTR::operator !=
- CComBSTR::operator &
- CComBSTR::operator +=
- CComBSTR::operator <
- CComBSTR::operator =
- CComBSTR::operator ==
- CComBSTR::operator >

#サンプル
サンプルプログラム全体を下に示します。

##ヘッダーファイル

```C++
// stdafx.h : 標準のシステム インクルード ファイルのインクルード ファイル、または
// 参照回数が多く、かつあまり変更されない、プロジェクト専用のインクルード ファイル
// を記述します。
//

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

// TODO: プログラムに必要な追加ヘッダーをここで参照してください
#include <atlbase.h>
#include <atlstr.h>
```

##CPP ファイル

```C++
// TestCComBSTR.cpp : アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"

//
//  CComBSTR の使用例
//  ==================
int main()
{
	// AllocSysString で BSTR を初期化
	BSTR str = SysAllocString(L"Hello");
	wprintf_s(L"%s\n", str);  // BSTR を表示
	SysFreeString(str);  // 解放

	// CComBSTR で BSTR を初期化
	BSTR bstr1 = CComBSTR(L"Hello").Copy();
	wprintf_s(L"%s\n", bstr1);  // BSTR を表示

	// BSTR から CComBSTR を作成
	CComBSTR cstr1(bstr1);
	wprintf_s(L"%s\n", cstr1);  // CComBSTR は自動的に BSTR に変換されて表示される。(警告はでるが)

	// 比較
	if (cstr1 == bstr1)
	{
		wprintf_s(L"True\n");
	}
	else
	{
		wprintf_s(L"False\n");
	}

	// CComBSTR の中身を取得
	WCHAR* bstr = cstr1.m_str;
	wprintf_s(L"m_str: %s\n", bstr);

	// 長さを取得
	wprintf_s(L"Length: %d\n", cstr1.Length());

	// 結合
	cstr1.AppendBSTR(bstr);
	wprintf_s(L"Append: %s\n", cstr1);

	// コピー
	BSTR bstr2 = cstr1.Copy();
	wprintf_s(L"Copy: %s\n", bstr2);

	// C スタイル文字列へ変換
	WCHAR cstyle[100];
	swprintf_s(cstyle, L"%s", cstr1);
	wprintf_s(L"C style: %s\n", cstyle);

	getchar();
	return 0;
}
```

![SampleCComBSTR.png](https://qiita-image-store.s3.amazonaws.com/0/62802/f91663ff-01cb-e4d1-970c-18084038b853.png)


Fig.1 サンプルの実行例

-