SafeArrayCreateVector や SafeArrayAccessData や SafeArrayUnaccessData は
COMのインターフェース内でしか使用できないのでしょうか?
lpsfArray = SafeArrayCreateVector(VT_BSTR, 0, sArray.GetSize());
if(NULL == lpsfArray)
{
return FALSE;
}
hRet = SafeArrayAccessData(lpsfArray, (void HUGEP **)&lpBSTRData);
if(FAILED(hRet))
{
return FALSE;
}
for (i = 0; i < sArray.GetSize(); i++)
{
lpBSTRData[i] = sArray.GetAt(i).AllocSysString();
}
SafeArrayUnaccessData(lpsfArray);
lpsfArrayはSAFEARRAYのポインタ
sArrayはCStringArray
lpBSTRDataはBSTRのポインタ
この処理をCOMのインターフェース内で実行した場合は予定の動作の
CStringArrayのデータをSAFEARRAYにコピーできます。
しかし、この処理をCOMのprivateな内部関数にすると動作しません。
実際この処理を4つのCStringArrayに対して行いたいので関数化したのですが、
無理なのでしょうか?
WIN2000SP4/VC++6.0SP5/MFC使用
よろしくお願いします
>SafeArrayCreateVector や SafeArrayAccessData や SafeArrayUnaccessData は
>COMのインターフェース内でしか使用できないのでしょうか?
そんなことはありません。
>しかし、この処理をCOMのprivateな内部関数にすると動作しません。
どんなコードを書いて、どんな状況になってしまっているのでしょう?
元ソースを参考にいろいろ試した結果、期待通りに動くものが完成したのですが、
SAFEARRAYの基本的な使用法がわからないのでソースの意味がわかりません。
以下にソースの抜粋
idlファイル内に以下のメンバがある構造体STXXXXを定義し
SAFEARRAY(BSTR) lpsfaName; <----(1)
このSTXXXXのポインタを引数とするCOMのインターフェース
GetXXX(LPSTXXXX lpStXxxx)を作成しました。
このGetXXXで共通関数をよびCStringArrayにデータをセットします。
そしてCOMのprivateな内部関数SetArrayDataに渡し
SetArrayData(saName, &lpStXxxx->lpsfaName); <----(2)
SAFEARRAYにCStringArrayのデータをSAFEARRAYにコピーしています。
BOOL COAMaterialDataCom::SetArrayData(CStringArray& szArray, SAFEARRAY**
lpsfArray) <----(3)
{
BSTR* lpBSTRData = NULL;
HRESULT hResult;
if( szArray.GetSize() != 0 )
{
*lpsfArray = SafeArrayCreateVector(VT_BSTR, 0, szArray.GetSize());
if(NULL == lpsfArray) return FALSE;
hResult = SafeArrayAccessData(*lpsfArray, (void HUGEP **)&lpBSTRData);
if(FAILED(hResult)) return FALSE;
for (int i = 0; i < szArray.GetSize(); i++)
lpBSTRData[i] = szArray.GetAt(i).AllocSysString();
SafeArrayUnaccessData(*lpsfArray);
}
return TRUE;
}
わからない事
1.(1)の定義は何?
SAFEARRAYは構造体のハズで(BSTR)は何をしている?マクロ?
2.(1)の定義を仮にSAFEARRAYのポインタ宣言をしているとすると、
(3)のSAFEARRAY**の意味はわかりますが、*lpsfArrayはポインタを指しているはずなのに
SafeArrayCreateVectorの戻り値はポインタではないのでなぜ問題ないの?
3.このCOMはVBから呼び出した時に期待通りの動作をします
VB側ではCOMに渡す引数を作成する時にlpsfaNameには何もセットしていません。
(1)の定義を仮にSAFEARRAYのポインタ宣言をしているとすると実体を作成してセット
しないとまずいはずなのになぜうまく機能しているの?
ネットやMSDNでSAFEARRAYで検索してもなかなかみつかりませんでした。
何かここでわかるよなどないでしょうか?
よろしくお願いします
以前私も悩みました。わかる部分だけ書きます。
(トンチンカンだったらごめんなさい)
> 1.(1)の定義は何?
> SAFEARRAYは構造体のハズで(BSTR)は何をしている?マクロ?
これはidlファイルなのでMIDLの記述です。
SAFEARRAY(BSTR)でBSTRのSAFEARRAY*をあらわしています。
コンパイルするとSAFEARRAY*として扱われます。
> 2.(1)の定義を仮にSAFEARRAYのポインタ宣言をしているとすると、
> (3)のSAFEARRAY**の意味はわかりますが、*lpsfArrayはポインタを指しているはずなの
に
> SafeArrayCreateVectorの戻り値はポインタではないのでなぜ問題ないの?
SafeArrayCreateVector は SAFEARRAY* ですよね?
問題ないと思います。
> 3.このCOMはVBから呼び出した時に期待通りの動作をします
> VB側ではCOMに渡す引数を作成する時にlpsfaNameには何もセットしていません。
> (1)の定義を仮にSAFEARRAYのポインタ宣言をしているとすると実体を作成してセット
> しないとまずいはずなのになぜうまく機能しているの?
SAFEARRAYを関数SetArrayData内で作成してlpsfArrayに返すという動作なので、
実態を用意しなくてもいいのだと思います。
逆に実態があった場合は、SafeArrayDestroyなどで削除しなければならないはずです。
回答ありがとうございます。
>SafeArrayCreateVector は SAFEARRAY* ですよね?
MSDNを見ると
SAFEARRAY SafeArrayCreateVector(
VARTYPE vt,
long lLbound,
unsigned int cElements
);
のようになっており、ポインタではないのです。
MSDNが間違いなのかな?
>逆に実態があった場合は、SafeArrayDestroyなどで削除しなければならないはずです。
malloc等の場合はポインタが返ってきて使用した後freeします。
SafeArrayCreateVectorの場合はいらないのですか?
質問ばかりですが宜しくお願いします。
> MSDNを見ると
> SAFEARRAY SafeArrayCreateVector(
> VARTYPE vt,
> long lLbound,
> unsigned int cElements
> );
> のようになっており、ポインタではないのです。
> MSDNが間違いなのかな?
あれ?
私の使っているMSDN(2001年10月 日本語)では SAFEARRAY* になってますよ。
説明文も、
Return Value
Points to the array descriptor, or Null if the array could not be created.
です。
(Platform SDK: Automation内です。これ以降のMSDNは .NET なので使ってません)
そうなんなんですね、こ
こちらで使用しているものは付属していた1998/7/19版で相当古いようです。
SafeArrayCreateVectorはポインタを返却する事はわかりました。
すると、idl内での定義もポインタなので実体はどこにあるんでしょう?
難しいです
実体って、SAFEARRAY の実体のことですよね?
メモリ上でしょ?
SAFEARRAY の宣言は、VC++ のヘッダ(=OLE 関係のどれか)を検索すれば出てきます。
インストールしていたPlatform SDKの最新版のヘルプにSafeArrayCreateVectorがありました
ポインタで返却されていました。
>実体って、SAFEARRAY の実体のことですよね?
>メモリ上でしょ?
実体って表現がよくないでした。わからないのは
SafeArrayCreateVectorは引数に指定した個数(固定)の一次元配列を作成し、
このポインタをかえす。malloc等の場合はfreeをするのですが
SafeArrayCreateVectorはいつメモリを解放しているのでしょうか?
この点を意識しなく使用できるのでセーフ(安全)配列?
何度もすみません、よろしくい願い致します
SafeArrayDestroyで削除する必要があるはずです。
ただし、VB側に渡した後はVBが面倒見てくれていると思います。
>ただし、VB側に渡した後はVBが面倒見てくれていると思います
ここら辺がわからないのです。
VB側では何をしているのでしょう?
VBが勝手に解放してくれるのでしょうか?
VBの質問になってしまいましたがよろしくお願いします。
VBに引き渡したオブジェクトの解放は、VBがやってくれます。
SAFEARRAY だけでなく、文字列(=BSTR)もそうだし、オブジェクトインスタンスの参
照もそうです。
# むしろ、SAFEARRAY や BSTR も「一種のオブジェクトである」と考えた方がすっきり
するかもしれません。
こまかい事ですが最終確認です。
VBにはSafeArrayCreateVectorした配列のポインタが渡り、
SafeArrayCreateVectorで確保したメモリ領域はVBが解放してくれる。
VBのプログラムを書いている人ではなくVBが解放してくれる。
したがって、最初に提示したソースはおかしなことはしていない。
これで最後にします。よろしくお願いします。
>VBにはSafeArrayCreateVectorした配列のポインタが渡り、
>SafeArrayCreateVectorで確保したメモリ領域はVBが解放してくれる。
>VBのプログラムを書いている人ではなくVBが解放してくれる。
その通りです。
>したがって、最初に提示したソースはおかしなことはしていない。
ソースの方は、異常が無いかどうか断言出来るほどよく見てません。
気になるのは *lpsfArray が示すところにすでに SAFEARRAY の実態があったときですね。
SafeArrayCreateVector の前に開放しないとリークになるかな?
(VBから渡された場合ってどうなるんだろう?やったことないです。)