配列の参照渡しで配列の先頭要素以外を渡したいときは?


ひで40  2003-11-08 01:17:27  No: 109814

Public Sub Foo(ByRef Buffer() as BYTE)
というようなライブラリがあるのですが、ここで引数を渡すときに
例えば
Dim MyBuf(20) AS Byte
としたとき、
Foo MyBuf
は問題ないのですが、配列の先頭でなく、途中の要素のアドレスを
渡したいときはどのように表記すれば良いのでしょうか。
例えば
Foo MyBuf(10)
などと書くとエラーになってしまいます。


しゅう  2003-11-08 04:11:46  No: 109815

これでどうですか?

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)


しゅう  2003-11-08 04:18:21  No: 109816

MyBuf(10) 'これは配列でなくここではバイト型ですよー。


ひで40  2003-11-08 04:30:20  No: 109817

しゅうさん、回答ありがとうございます。
確かにそのようなやり方は可能ですが無駄が多いです。

実際はライブラリ関数はBufferにデータを書き込んでくれるのです。
例えば書き込みが10バイトだとすると、
100バイトの配列を用意しておいて、渡すアドレスを10ずつ増やしながら
関数を呼んでいくような使い方がしたいのです。
C言語なら簡単にできることがVBだと、どうやって書いたら良いのか
分からないのです。


魔界の仮面弁士  2003-11-08 04:47:41  No: 109818

> 実際はライブラリ関数はBufferにデータを書き込んでくれるのです。
バイト配列で引き渡すのではなく、Streamでやりとりするようにすれば良いかと。


red-fish  2003-11-08 05:08:03  No: 109819

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

というトリッキーな書き方もなくはないです。
副作用は知りません(^^;


ひで40  2003-11-08 05:10:24  No: 109820

魔界の仮面弁士様

コメントありがとうございます。
「Stream」とは初耳です。.NETの機能でしょうか。
環境を書かなかったので申し訳ありません。VB6です。
それと、ライブラリといっているのは市販のもので、
ソースはないので関数側を書き換えることはできません。


ひで40  2003-11-08 05:15:51  No: 109821

red-fish 様
回答ありがとうございます。

ご指摘の方法で副作用は無いと思いますが、
魔界の仮面弁士様へのコメントでも書いたように関数側は
書き換えられないのです。
呼び出し側の書き方で実現するのは無理なのでしょうか?


red-fish  2003-11-08 05:42:10  No: 109822

呼び出し側の書き方で実現したつもりです。

ただ新たに領域が生成されていることには変わりないので
しゅうさんのが無駄というなら、これも無駄かも。


魔界の仮面弁士  2003-11-08 09:55:19  No: 109823

> 「Stream」とは初耳です。.NETの機能でしょうか。
IStreamインターフェイスです。VB6だと、ADODB.Streamとか。

> ソースはないので関数側を書き換えることはできません。
定義として『Sub Foo(ByRef Buffer() as BYTE)』とありますが、
この相手側というのは、ActiveX DLLですか?
それとも、Declareで呼び出すタイプの物ですか?

相手側の実装にもよりますが、SafeArrayとして渡す事になっているのなら、
対処のしようが無いと思います。一方、Declareで呼び出すタイプで、かつ、
配列の先頭アドレスを渡すタイプの物であれば、配列の途中要素を参照渡しれば、
そのアドレス以降の部分に出力してくれるかもしれません。

> C言語なら簡単にできることがVBだと、
ちなみに、その部分の呼び出しをC言語で記述した場合は、どのようになるのですか?


しゅう  2003-11-08 11:28:41  No: 109824

こんな感じで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


しゅう  2003-11-08 11:37:00  No: 109825

書き忘れました。
相手側のライブラリ関数を編集出来ないとわかっているならば、
上記はすごく自然だと思います。


ひで40  2003-11-08 22:31:06  No: 109826

red-fish様、 しゅう様、魔界の仮面弁士様
遅い時刻に丁寧なコメントありがとうございました。

red-fish様、 しゅう様のコードは理解できますし、
方法がなければそのような手段を取るしかないですね。
私が知りたかったのはそれ以外にうまくアドレスを渡せる
表現があるのではないかということなのです。

魔界の仮面弁士 様
>定義として『Sub Foo(ByRef Buffer() as BYTE)』とありますが、
>この相手側というのは、ActiveX DLLですか?
>それとも、Declareで呼び出すタイプの物ですか?
ActiveXです。SafeArrayとして渡す事になっています。

>ちなみに、その部分の呼び出しをC言語で記述した場合は、
>どのようになるのですか?
C言語だと、関数側も引数はポインタになっているだろうから、
呼ぶ方もポインタ変数を適宜変えながら呼べば済むといった
イメージで書きました。

実はライブラリというのはIEEE1394カメラから画像を入力する
ライブラリでして、1フレームのデータ転送完了すると、イベント
が入ります。そのハンドラの中で質問の関数(引数などは省略して
います)を呼んで、データを受け取る仕様です。
複数フレームの画像データを連続する領域に保持できるように
質問のようなことがやりたかったのです。またデータ量が多いので
コピー等は避けたかったのです。

アドレス渡す適当な方法は無いようなので、プログラムのデータ構
造を変えて考え直します。ありがとうございました。


魔界の仮面弁士  2003-11-08 23:05:59  No: 109827

> C言語だと、関数側も引数はポインタになっているだろうから、
> 呼ぶ方もポインタ変数を適宜変えながら呼べば済むといった
? ごめんなさい、話が見えないです…。m(_ _;)m

今回渡す引数は、「SafeArrayのポインタ」つまり
LPSAFEARRAY(もしくはSAFEARRAY*)なのですよね……?

では、『ポインタ変数を適宜変えながら呼ぶ』というのは、
具体的には、(C言語で)どのような記述になるのでしょうか。
もし、C言語でのサンプルを提示できるのであれば、
それを見せて貰えれば、VB版として移植するための方法を
提示できるかもしれませんよ。

(でも、本当に『C言語なら簡単にできること』なのですか?『C++』ではなく?)


ひで40  2003-11-09 04:15:59  No: 109828

魔界の仮面弁士様

たびたび、すいません。
「SafeArray」について、良く知らないで発言していました。
ライブラリマニュアルに「SafeArray」とありましたが、
特に意識しないで使っていました。
あらためて、Googleで検索して、SafeArrayは構造体で、次元の数と
その中の境界値、そして、配列の実データへのポインタなどが納め
られていることを知りました。
http://homepage1.nifty.com/macbs/auto1.htmが参考になりました
これではC言語でもめんどうそうですね。
ライブラリ内部でエラーチェックしているのでしょう。


匿名太郎  2003-11-09 05:27:58  No: 109829

横から失礼します
>>(でも、本当に『C言語なら簡単にできること』なのですか?『C++』ではなく?)
char Array[10];
Foo(Array+2);  // 先頭から2番目を渡す
みたいに簡単に出来るという意味だと思います

SAFEARRAYは普通の配列とまったく違いますから、
最初からこれを考慮してコーディングするしか無いでしょう。
ActiveXではプロセスをまたいだアクセスを可能にしているので
大きさのわからない配列は扱えません。
(これはVBが使うタイプライブラリマーシャリングでの限界です)


匿名太郎  2003-11-09 06:22:07  No: 109830

まちがえました
>>SAFEARRAYは普通の配列とまったく違いますから、
VBではSAFEARRAYが普通の配列でした。


ひで40  2003-11-09 17:37:43  No: 109831

匿名太郎 様
コメントありがとうございます。
更に理解が深まりました。
普通の配列と考えていたのがそもそも間違いなのですね。
プログラムのデータ構造を変えて考え直します。
ありがとうございました。


しゅう  2003-11-10 18:43:49  No: 109832

ひで40様
最初の質問に対していきなり代案を記してしまいました。
ごめんなさい。只今、反省中です。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加