アクティブXでOO4Oを使ってDBよりデータを取得します。
そのアクティブXで取得したデータをC++で使用したいのですが
取得データを文字列の配列やLONGの配列に入れて渡したいのです。
一応呼び出し自体はLONG変数のみならできたのですが
配列となるとうまくいきません。
どのようなコードを書けばいいのでしょうか?
以前自分が参考にしたページですよろしかったらどうぞ
http://homepage2.nifty.com/DSS/VCPP/DLL/dllvcstr.htm
文字列ができたとしても配列と関係あるんでしょうか?
MSDNも理解できないくらい頭が悪いのでいまいち理解できません。
Cでは文字列を Char 型の配列と考えます。
文字列の配列ならポインタのポインタという表現に
なるでしょうから、ポインタが分からなければ
C側のコードは書けないでしょう。Cのお勉強して
ください。
アクティブXはVBで作ってるんですが
ポインタのない言語にポインタを渡してもいいんですか?
実際にポインタのポインタで文字列の配列を渡すサンプルソースとかないでしょうか?
C++では、CHAR配列を文字列として扱うことが多いですけど、
それは「文字の配列」であって、「文字列の配列」とは違うのでは。
VBの文字列配列をそのままDLL側に渡したい(あるいは受け取りたい)なら、SAFEARRAYを使ってください。C++側では、SafeArray系APIを使ってその配列を操作できます。
あるメソッドの引数が、DLL側で、LPSAFEARRAY FAR * として宣言されている場合、VBからは ByRef x() As String のように見えます。
http://www.microsoft.com/japan/msdn/vs_previous/vbasic/docs/dll/#8
作ってみましたがうまくいきません。
アクティブXDLL(VB6.0)
////////////////////////////////////////////////////
Public Function test(ByRef Data() As String) As Long
Data(0) = "あ"
Data(1) = "い"
Data(2) = "う"
Data(3) = "え"
Data(4) = "お"
test = 1
End Function
/////////////////////////////////////////////////////
呼び出しVC6.0
// C++から COMコンポーネントにアクセスする
// (C)Yajima, Satoshi
#include "stdio.h"
#include "windows.h"
#include "ATLBASE.H"
#include "objbase.h"
//#include <tchar.h>
//project1.dllを元に、必要な定義ファイルを生成する
#import "Project1.dll" no_namespace named_guids raw_interfaces_only
// メイン処理
void main(){
USES_CONVERSION;
long z; //プロシージャの引数、戻り値用
HRESULT hResult; // COM 戻り値用変数
_DBClass* pClass1; // DLLのオブジェクト名
// BYTE * k[100];
BSTR * BstrArray[12150];
VARIANT data;
SAFEARRAY * psa ;
SAFEARRAYBOUND rgb[1];
rgb[0].cElements = 12150; // 作成するSAFEARRAYの要素数 = 32
rgb[0].lLbound = 0; // 作成するSAFEARRAYの添字の下限値 = 0
ZeroMemory(&data,sizeof(data));
// COMの初期化
::CoInitialize(0);
// インスタンスの作成(CLSIDとIIDを指定して、ポインタ pClass0 を取得)
// [VB] Set obj = New Project1.Class1
hResult = ::CoCreateInstance((REFCLSID) CLSID_DBClass, 0, CLSCTX_INPROC_SERVER,
(REFIID) IID__DBClass, (LPVOID*)&pClass1);
if( ! SUCCEEDED(hResult) ) {
printf("ERROR occured = %08x\n", hResult);
}
psa = SafeArrayCreate(VT_BSTR,1,rgb); // SAFEARRAY作成
if(psa == NULL) // SAFEARRAY作成結果判定
{
printf("SAFEARRAY作成失敗\n");
return ;
}
// 作成したSAFEARRAYのポインタ取得及びロック
SafeArrayAccessData(psa,(void**)&BstrArray);
pClass1->test(&psa,&z);
printf("%s\n",OLE2T(*BstrArray[0]));
printf("%s\n",OLE2T(*BstrArray[1]));
// 終了処理
pClass1->Release();
SafeArrayUnaccessData(psa); // SAFEARRAYアンロック
// COMの終了処理
::CoUninitialize();
}
すいません。書き込み途中に送信してしまいました。
管理人さんよかったら消してください。
即席でパクリもののソースに手を加えたんですが
まだあまり理解していないので何か勘違いしているかもしれません。
配列の一番目だけがうまくいきます。
2番目以降は取得でうまくいってないみたいですが原因はどこにあるでしょうか?
それともソースそのものが何か勘違いしてるでしょうか?
文字配列ならこんな感じでいかがでしょうか?
これも即席でパクリもののソースに手を加えたものです...
== VB ========================
Option Explicit
Public Function test_sub(strBuf As String) As Long
strBuf = "てすと"
test_sub = 0
End Function
== VC ========================
#include <stdio.h>
#include <atlbase.h>
#import "Project1.dll"
using namespace Project1;
void main()
{
USES_CONVERSION;
if (SUCCEEDED(::CoInitialize(NULL)))
{
{
_Class1Ptr pClass1(__uuidof(Class1));
BSTR bbb = 0;
printf("%d\n", pClass1->test_sub(&bbb));
LPTSTR paaa = OLE2T(bbb);
}
::CoUninitialize();
}
}
文字列は私もできたので、せめてバイト配列を渡すコードを書きたいのですが
どうにか成らないでしょうか?
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/office97/html/SFEA1.asp
のAllocating Arraysを参考にしました
取得は出来るというレベルで本当にこれで良いと言う保証は出来ませんが...
== VB ========================
Option Explicit
Public Function test_sub2(ByRef Data() As String) As Long
Data(0) = "ああ"
Data(1) = "い"
Data(2) = "う"
Data(3) = "え"
Data(4) = "お"
test_sub2 = 1
End Function
== VC ========================
#include <stdio.h>
#include <atlbase.h>
#import "Project1.dll"
using namespace Project1;
void main()
{
USES_CONVERSION;
if (SUCCEEDED(::CoInitialize(NULL)))
{
{
_Class1Ptr pClass1(__uuidof(Class1));
unsigned long l;
BSTR bstr;
LPSAFEARRAY psa;
SAFEARRAYBOUND sa;
sa.lLbound = 0;
sa.cElements = 10;
psa = SafeArrayCreate(VT_BSTR, 1, &sa);
printf("%d\n", pClass1->test_sub2(&psa));
for (l = sa.lLbound; l < sa.cElements; l++){
if (FAILED(SafeArrayGetElement(psa, (long *)&l, &bstr)))
return;
printf("%s\n", OLE2T(bstr));
}
}
::CoUninitialize();
}
}
ごめんなさい嘘ついしゃいました。
参照はAllocating ArraysではなくUsing Arrays of Stringsの間違いです。
非常に苦労しましたがまぐれで?できました。
誰か意味がわかる人がいたら教えてください。
VB側
Public Type tagKDATA
name As String
End Type
Public Type tagDATA
data(9) As tagKDATA
End Type
Public Function test(ByRef data As tagDATA) As Long
data.data(0).name = "あいうえお"
data.data(1).name = "かきくけこ"
data.data(2).name = "さしすせそ"
data.data(3).name = "たちつてと"
data.data(4).name = "なにぬねの"
data.data(5).name = "はひふへほ"
test = 1
End Function
VC
#include "stdio.h"
#include "windows.h"
#include "ATLBASE.H"
#include "objbase.h"
#import "Project1.dll" no_namespace named_guids raw_interfaces_only
void main(){
USES_CONVERSION;
long z;
HRESULT hResult;
_Class1* pClass1;
tagDATA * BstrArray;
LPSAFEARRAY psa ;
SAFEARRAYBOUND rgb[1];
rgb[0].cElements = 10;
rgb[0].lLbound = 0;
::CoInitialize(0);
hResult = ::CoCreateInstance((REFCLSID) CLSID_Class1, 0, CLSCTX_INPROC_SERVER,
(REFIID) IID__Class1, (LPVOID*)&pClass1);
if( ! SUCCEEDED(hResult) ) {
printf("ERROR occured = %08x\n", hResult);
return ;
}
psa = SafeArrayCreate(VT_BSTR,1,rgb);
if(psa == NULL)
{
printf("SAFEARRAY作成失敗\n");
return ;
}
SafeArrayAccessData(psa,(void**)&BstrArray);
pClass1->test(BstrArray,&z);
printf("%s\n",OLE2T(BstrArray->data[0].name));
printf("%s\n",OLE2T(BstrArray->data[1].name));
printf("%s\n",OLE2T(BstrArray->data[2].name));
printf("%s\n",OLE2T(BstrArray->data[3].name));
pClass1->Release();
SafeArrayUnaccessData(psa);
::CoUninitialize();
}
VC側でビルドするとtlhという拡張子のファイルができます。
そのファイルの中にDLL側の引数の型の宣言?が出てきます。
その型はVC側で宣言なしに何故か使用できます。クラスビューには出てきません。
その型を使用すると簡単にできます。
構造体にして引数を配列にしなければうまくいきました。
構造体の中に配列を作ります。
神!シェンロンですね!!
36NETさんありがとうございました。
またやばくなったら教えてください。