Public Sub Foo(ByRef Buffer() as BYTE)
というようなライブラリがあるのですが、ここで引数を渡すときに
例えば
Dim MyBuf(20) AS Byte
としたとき、
Foo MyBuf
は問題ないのですが、配列の先頭でなく、途中の要素のアドレスを
渡したいときはどのように表記すれば良いのでしょうか。
例えば
Foo MyBuf(10)
などと書くとエラーになってしまいます。
これでどうですか?
Dim MyBuf0(15) As Byte
Dim Mybuf1(8 To 11) As Byte
For i = 8 To 11
Mybuf1(i) = Mybuf0(i)
Next
Call Foo(Mybuf1)
MyBuf(10) 'これは配列でなくここではバイト型ですよー。
しゅうさん、回答ありがとうございます。
確かにそのようなやり方は可能ですが無駄が多いです。
実際はライブラリ関数はBufferにデータを書き込んでくれるのです。
例えば書き込みが10バイトだとすると、
100バイトの配列を用意しておいて、渡すアドレスを10ずつ増やしながら
関数を呼んでいくような使い方がしたいのです。
C言語なら簡単にできることがVBだと、どうやって書いたら良いのか
分からないのです。
> 実際はライブラリ関数はBufferにデータを書き込んでくれるのです。
バイト配列で引き渡すのではなく、Streamでやりとりするようにすれば良いかと。
Public Sub Foo(ByRef Buffer() as BYTE)
を
Public Sub Foo(ByRef Buffer() as BYTE, , ByVal Start As Integer)
とするのが、一番いいと思うのですが、
Private Sub Command1_Click()
Dim i As Integer
Dim b(99) As Byte
'ダミーdata作成
For i = 0 To 99
b(i) = i
Next
For i = 0 To 9
Foo MidB(b, i * 10 + 1, 10)
Debug.Print String$(10, "-")
Next
End Sub
Private Sub Foo(ByRef Buffer() As Byte)
Dim i As Integer
For i = 0 To 9
Debug.Print Buffer(i)
Next
End Sub
というトリッキーな書き方もなくはないです。
副作用は知りません(^^;
魔界の仮面弁士様
コメントありがとうございます。
「Stream」とは初耳です。.NETの機能でしょうか。
環境を書かなかったので申し訳ありません。VB6です。
それと、ライブラリといっているのは市販のもので、
ソースはないので関数側を書き換えることはできません。
red-fish 様
回答ありがとうございます。
ご指摘の方法で副作用は無いと思いますが、
魔界の仮面弁士様へのコメントでも書いたように関数側は
書き換えられないのです。
呼び出し側の書き方で実現するのは無理なのでしょうか?
呼び出し側の書き方で実現したつもりです。
ただ新たに領域が生成されていることには変わりないので
しゅうさんのが無駄というなら、これも無駄かも。
> 「Stream」とは初耳です。.NETの機能でしょうか。
IStreamインターフェイスです。VB6だと、ADODB.Streamとか。
> ソースはないので関数側を書き換えることはできません。
定義として『Sub Foo(ByRef Buffer() as BYTE)』とありますが、
この相手側というのは、ActiveX DLLですか?
それとも、Declareで呼び出すタイプの物ですか?
相手側の実装にもよりますが、SafeArrayとして渡す事になっているのなら、
対処のしようが無いと思います。一方、Declareで呼び出すタイプで、かつ、
配列の先頭アドレスを渡すタイプの物であれば、配列の途中要素を参照渡しれば、
そのアドレス以降の部分に出力してくれるかもしれません。
> C言語なら簡単にできることがVBだと、
ちなみに、その部分の呼び出しをC言語で記述した場合は、どのようになるのですか?
こんな感じでMyBuf1を使用する事は、自分は無駄に感じません。
すごく一般的だと思います。
メモリ使用量は単純に1.1倍になるだけの様な感じがします。
(詳しくはわかりませんが。。。)
メモリ使用量が多い、処理時間が気になる等の特別な理由があるのでしょうか?
処理時間が気になる様であればFor-Nextの部分を
RtlMoveMemoryにすれば良いと思います。
Dim MyBuf0(99) As Byte
Dim MyBuf1(9) As Byte
Dim i As Integer
Dim j As Integer
For i = 0 To 9
For j = 0 To 9
MyBuf1(j) = MyBuf0(i * 10 + j)
Next
Call Foo(MyBuf1)
For j = 0 To 9
MyBuf0(i * 10 + j) = MyBuf1(j)
Next
Next
書き忘れました。
相手側のライブラリ関数を編集出来ないとわかっているならば、
上記はすごく自然だと思います。
red-fish様、 しゅう様、魔界の仮面弁士様
遅い時刻に丁寧なコメントありがとうございました。
red-fish様、 しゅう様のコードは理解できますし、
方法がなければそのような手段を取るしかないですね。
私が知りたかったのはそれ以外にうまくアドレスを渡せる
表現があるのではないかということなのです。
魔界の仮面弁士 様
>定義として『Sub Foo(ByRef Buffer() as BYTE)』とありますが、
>この相手側というのは、ActiveX DLLですか?
>それとも、Declareで呼び出すタイプの物ですか?
ActiveXです。SafeArrayとして渡す事になっています。
>ちなみに、その部分の呼び出しをC言語で記述した場合は、
>どのようになるのですか?
C言語だと、関数側も引数はポインタになっているだろうから、
呼ぶ方もポインタ変数を適宜変えながら呼べば済むといった
イメージで書きました。
実はライブラリというのはIEEE1394カメラから画像を入力する
ライブラリでして、1フレームのデータ転送完了すると、イベント
が入ります。そのハンドラの中で質問の関数(引数などは省略して
います)を呼んで、データを受け取る仕様です。
複数フレームの画像データを連続する領域に保持できるように
質問のようなことがやりたかったのです。またデータ量が多いので
コピー等は避けたかったのです。
アドレス渡す適当な方法は無いようなので、プログラムのデータ構
造を変えて考え直します。ありがとうございました。
> C言語だと、関数側も引数はポインタになっているだろうから、
> 呼ぶ方もポインタ変数を適宜変えながら呼べば済むといった
? ごめんなさい、話が見えないです…。m(_ _;)m
今回渡す引数は、「SafeArrayのポインタ」つまり
LPSAFEARRAY(もしくはSAFEARRAY*)なのですよね……?
では、『ポインタ変数を適宜変えながら呼ぶ』というのは、
具体的には、(C言語で)どのような記述になるのでしょうか。
もし、C言語でのサンプルを提示できるのであれば、
それを見せて貰えれば、VB版として移植するための方法を
提示できるかもしれませんよ。
(でも、本当に『C言語なら簡単にできること』なのですか?『C++』ではなく?)
魔界の仮面弁士様
たびたび、すいません。
「SafeArray」について、良く知らないで発言していました。
ライブラリマニュアルに「SafeArray」とありましたが、
特に意識しないで使っていました。
あらためて、Googleで検索して、SafeArrayは構造体で、次元の数と
その中の境界値、そして、配列の実データへのポインタなどが納め
られていることを知りました。
(http://homepage1.nifty.com/macbs/auto1.htmが参考になりました)
これではC言語でもめんどうそうですね。
ライブラリ内部でエラーチェックしているのでしょう。
横から失礼します
>>(でも、本当に『C言語なら簡単にできること』なのですか?『C++』ではなく?)
char Array[10];
Foo(Array+2); // 先頭から2番目を渡す
みたいに簡単に出来るという意味だと思います
SAFEARRAYは普通の配列とまったく違いますから、
最初からこれを考慮してコーディングするしか無いでしょう。
ActiveXではプロセスをまたいだアクセスを可能にしているので
大きさのわからない配列は扱えません。
(これはVBが使うタイプライブラリマーシャリングでの限界です)
まちがえました
>>SAFEARRAYは普通の配列とまったく違いますから、
VBではSAFEARRAYが普通の配列でした。
匿名太郎 様
コメントありがとうございます。
更に理解が深まりました。
普通の配列と考えていたのがそもそも間違いなのですね。
プログラムのデータ構造を変えて考え直します。
ありがとうございました。
ひで40様
最初の質問に対していきなり代案を記してしまいました。
ごめんなさい。只今、反省中です。
ツイート | ![]() |