Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
BSTR 覚え書き
2002.2.19 kanegon create
2002.2.23 kanegon update
BSTR は見かけ上(Windowsヘッダ上)、LPOLESTR と等しい。
typedef WCHAR OLECHAR; // ※
typedef OLECHAR __RPC_FAR * LPOLESTR;
typedef const OLECHAR __RPC_FAR * LPCOLESTR;
※ 16bit Platform では OLECHAR == char
しかし、実際には先頭に文字列長さを保持しており、この2つを混同しないこと。
BSTR のポインタはメモリ上の先頭を指していないため、BSTR を要求する関数に
LPOLESTR を渡してはならない。また、その関係で BSTR のメモリ管理は完全に別物
である。通常のメモリアロケート関数で処理しないこと。
ただし、LPOLESTR を要求する関数に BSTR を渡すことは問題ない。
LPOLESTR
↓
┌──────────┬─┐
│ string │\0│
└──────────┴─┘
BSTR
↓
┌───┬──────────┬─┐
│length│ string │\0│
└───┴──────────┴─┘
※ lentth は終端 '\0' を含まない string の byte 数
BSTR の領域の取得/解放は SysAllocString()/SysFreeString() または
その関連 API を使用して行なう。
BSTR SysAllocString(const OLECHAR* psz);
BSTR SysAllocStringLen(const OLECHAR* psz, UINT len);
BSTR SysAllocStringByteLen(LPCSTR psz, UINT len);
INT SysReAllocString(BSTR* pbstr, const OLECHAR* psz);
INT SysReAllocStringLen(BSTR* pbstr, const OLECHAR* psz, UINT len);
void SysFreeString(BSTR bstr);
UINT SysStringByteLen(BSTR bstr);
UINT SysStringLen(BSTR bstr);
※ このあたり、パラメタおよび戻り値の型が MSDN とヘッダで軒並み異なって
いる。仕様変更でもあったのか?
SysReAllocString() の戻り値は何者?
ここで、char* から BSTR の変換には以下を使用できるように思われる。
BSTR str = ::SysAllocStringByteLen(psz, strlen(psz) * sizeof(OLECHAR));
しかし、この関数は第一パラメタのバイナリ列を BSTR にそのままコピーするだけで
ANSI-UNICODE 変換とかするわけでないのでこの目的には使えない。注意すること。
通常の VC++ のコーディングでは、このあたりの変換はマクロやラッパクラスを使っ
て行なうが、API のみで実装する場合、以下のような感じになる(たぶん)。
[char* => BSTR]
size = ::MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0) - 1;
bstr = ::SysAllocStringByteLen(NULL, size * sizeof(OLECHAR));
::MultiByteToWideChar(CP_ACP, 0, psz, -1, bstr, size);
[BSTR => char*]
size = ::WideCharToMultiByte(CP_ACP, 0, bstr, -1, NULL, 0, NULL, NULL) - 1;
psz = new char[size + 1];
::WideCharToMultiByte(CP_ACP, 0, bstr, -1, psz, size + 1, NULL, NULL);
また、MSDN には情報が見つからなかったが、便利なユーティリティ関数も存在して
いる。以下は _bstr_t クラスなどの内部処理で使われているものである。
BSTR bstr = _com_util::ConvertStringToBSTR(psz); // throw(_com_error)
char* psz = _com_util::ConvertBSTRToString(bstr); // throw(_com_error)
これを使うと変換が1行で記述でき、かなり便利である。
# もちろん _bstr_t の方がもっと便利である。
このユーティリティ関数で確保した領域の解放にはそれぞれ SysFreeString()、
delete を使用するみたい。
SysFreeString(bstr);
delete[] psz;
同様に VC++ のヘッダを見ていくと、BSTR から BSTR の生成では、
BSTR str = ::SysAllocStringByteLen(reinterpret_cast(bstr),
::SysStringByteLen(bstr));
を使用している。
単純に SysAllocString() を使うのに比べると、効率悪そうだが、
SysAllocStringByteLen() の説明に
If psz is Null, a string of the requested length is allocated, but
not initialized. The string psz can contain embedded null characters,
and does not need to end with a Null. Free the returned string later
with SysFreeString.
とあり、BSTR は途中に NULL 文字を含んだ文字列を扱うことができるため、おそらく
その対処と思われる。
# SysAllocString() は終端 NULL の標準文字列しか扱えない。
このように途中に NULL 文字を含み、長さ情報を自前で保持する BSTR であるが、
終端の NULL も明確に保証されている。BSTR の領域を終端 NULL の LPOLESTR とし
て使用するのは問題ない。
SysAllocStringByLen() の長さパラメタの説明には
Number of bytes to copy from psz. A null character is placed afterwards,
allocating a total of len+1 bytes.
と記述がある。
さらに、元になる文字列がない場合の領域作成(0初期化なし)は
bstr = ::SysAllocStringByteLen(NULL, len);
である。このとき、len は生成する領域の byte 数を指定すること。
(終端の NULL はカウントしない)