C#で作成したライブラリをCOMとして呼び出しています。
C#側は、戻り値をstringの配列で返します。
public string[] GetStr()
{
}
自動で作成されたカスタムインターフェイスの定義上は、
virtual HRESULT __stdcall GetStr (
SAFEARRAY * * pRetVal ) = 0;
となっています。
VC++6.0側で、
CComBSTR out[4];
pClass1->GetSql((struct tagSAFEARRAY **)&out);
とコールしたところ
例外処理 (初回) は ComTest.exe (KERNEL32.DLL) にあります: 0xE06D7363: Microsoft
C++ Exception。
となってしまいました。
キャストの仕方がおかしいでしょうか。
SafeArrayをほしがっているところに無理やりCComBSTR型を渡してもダメなんじゃないか
な。
SAFEARRAY型を用意して、いちいち代入してあげないとイケなそう。
試しにやってみた。(ただしCOMを使っているわけではない)
#include <comdef.h>
#include <cstdlib>
#include <iostream>
#include <atlbase.h>
// 実験用関数
void test( LPSAFEARRAY* ppsa )
{
SAFEARRAY*& psa = *ppsa;
long lb, ub;
::SafeArrayGetLBound( psa, 1, &lb );
::SafeArrayGetUBound( psa, 1, &ub );
::SafeArrayLock( psa );
for ( long i = lb; i <= ub; i++ )
{
BSTR wcs;
::SafeArrayGetElement( psa, &i, ( void* )&wcs );
std::wcout << wcs << std::endl;
}
::SafeArrayUnlock( psa );
}
int main()
{
std::wcout.imbue( std::locale( japanese ) );
CComBSTR bs[ 4 ] = { Lあんぱん, L食パン, Lカレーパン, LABC };
SAFEARRAY* psa;
SAFEARRAYBOUND sab;
sab.cElements = 4;
sab.lLbound = 0;
psa = ::SafeArrayCreate( VT_BSTR, 1, &sab );
BSTR* data;
::SafeArrayAccessData( psa, ( void** )&data );
for ( long i = 0; i < 4; i++ )
{
data[ i ] = bs[ i ];
}
::SafeArrayUnaccessData( psa );
test( &psa );
::SafeArrayDestroy( psa );
return 0;
}
Blueさん、お試しありがとうございます。
Blueさんのご意見を参考に
SAFEARRAYと格闘していて遅くなりました。
ちなみに↓を参考にしてみました。
http://www.orin.jp/dev/tutorial_rao.html
以下ソースで配列で結果を受け取ることができました。
SAFEARRAY* pSa;
SAFEARRAYBOUND bound = { 3 ,0 };
pSa = SafeArrayCreate( VT_BSTR , 1, &bound );
CComBSTR* iArray;
result = m_pClass1->GetStr(&pSa);
SafeArrayAccessData( pSa, (void**)&iArray); // iArrayに戻り値が入っているのを確認。
SafeArrayUnaccessData( pSa );
SafeArrayDestroy( pSa );
う~ん。Blueさんの方が30分以上前に出来てる~。
SAFEARRAYなんて初めて触りました。勉強になりました。ありがとうございます。
解決時チェックを忘れました。チェックします。
あら。
値を設定したのを渡すのでなくて、値を設定してもらってから取得するのですね。
ちなみに、SafeArrayのラッパークラスがMFCにあります。(COleSafeArray)
VC6より新しい環境であれば、CComSafeArrayってのがあるらしいですが。
(CComBSTRやCComVariantほど重宝するものではないかなと。)