次の方法で共有


配列変数からのキャストについて

質問

2014年9月2日火曜日 9:59

開発環境

Win7 Pro、.NET FramWork4

現在VB6⇒VB.NETへ書き直しております

'COMポートから受信
Private Function RsRxd(pRxdBuff() As Byte, RxdSize As Long) As Long
'受信タイムアウト時は、-10が戻る
   
    Dim ComOcx As Object            'mscommへの参照を入れる
    Dim rxbuff As Variant        ←←.NETの場合、Object型で宣言
    Dim l As Long
    Dim lTime As Long
   
    lTime = timeGetTime()
    ComOcx.InputLen = RxdSize
    Do
        If ComOcx.InBufferCount >= RxdSize Then     'RxdSize受信するまでloop
            Exit Do
        End If
        'タイムアウトcheck:とりあえず15秒
        If (timeGetTime() - lTime) > 15000 Then
            RsRxd = -10     'タイムアウト
            Exit Function
        End If
    Loop
    rxbuff = ComOcx.Input     ←ここで『'System.String'のオブジェクトを型'System.Arrayにキャストできません'』
    For l = 0 To UBound(rxbuff)
        pRxdBuff(l) = rxbuff(l)
    Next

そこで、上記のVB6のプログラムにおいて、VB6ではエラーになりませんが、VB.NETの場合、変数に値を入れようとするとエラーが発生します。

VB6とVB.NETでのソースの違いは、変数宣言においてVB.NETではVariant型がない為、Object型で宣言しています。

イミディエイトウィンドウで『ComOcx.Input』を見ても、配列の場合、『??』と表示され、rxbuff(l)を中を見た場合、『48』、『70』等の数値が入っています。

配列でない変数に配列変数を入れようとしている為エラーになるのは分るのですが、どのようにキャストしたら良いか分らず、投稿させて頂きました。

初歩的な質問かもしれませんが、何卒宜しくお願い申し上げます。

すべての返信 (4)

2014年9月2日火曜日 17:16 ✅回答済み | 1 票

質問するときは開発環境のバージョンをきちんと書きましょう。.NET Frameworkのバージョンだけでは不十分です。多分VB.NET 2010あたりだとは思いますが……
まず、VB.NETには旧Visual Basicにおける邪悪なVariant型は存在しません。.NETのObject型はまったくの別物で、互換性がないことに注意してください。また、VB.NETではIntegerが32bitに、Longが64bitになります。
肝心の、コンパイルエラーだかランタイムエラーだかが発生しているとかいうVB.NETのほうのコードがきちんと提示されてないので、これは予測になりますが、System.String型(にマーシャリングされた)InputプロパティをSystem.Arrayに無理やりキャストするとかいうようなことをしているのですか?
もしString中の各文字(ASCII前提)をインデクサで取得したいだけなのであれば、

pRxdBuff(i) = CType(Val(comOcx.Input(i)), Byte)

のような形で書けると思います。
なお、.NET 2.0以降では、System.IO.Ports.SerialPortクラスが追加されているので、今後はそちらを使ったほうがよいと思います。無理に古いコンポーネントを使う必要はありません。なお、複雑なことをしようとする前に、まず入門サイトか何かで旧VBとVB.NETの根本的な違いをきちんと勉強してからにしたほうがよいと思います。


2014年9月2日火曜日 18:09 ✅回答済み

ComOcxというのはMS Comm Control 6.0(MSCOMM32.ocx)でしょうか?
であればInputを読み取る前の適当なところに

ComOcx.InputMode = MSCommLib.InputModeConstants.comInputModeBinary

というコードを挿入してください。
そうするとInputはバイト配列を返すようになります。

逆にMSCommLib.InputModeConstants.comInputModeTextが設定されているとInputは文字列と変換されて返されます。
UBoundの引数には配列を与えないといけないのに、文字列はArray(配列)にキャストできないので、その結果としてエラーとなります。

    rxbuff = ComOcx.Input 'InputModeConstants.comInputModeTextになっているとInputは文字列になる 
    For l = 0 To UBound(rxbuff)'←正しくはここで『'System.String'のオブジェクトを型'System.Arrayにキャストできません'』が発生します。
        pRxdBuff(l) = rxbuff(l)
    Next

元のVB6でバイナリで受信してたならcomInputModeBinaryを指定しましょう。

個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)


2014年9月2日火曜日 16:50

ソースと質問文が合っていない気がするのですが、キャストというか、とりあえずコレクションでしょうか?

(参考)
ジェネリック・クラスで変わるC#とVBのコレクション (2/4)
http://www.atmarkit.co.jp/ait/articles/0602/11/news011_2.html

#Listより高速なLinkedListもあります。ただし、良い面ばかりではありません。Listで性能が出なければ、試されてみてもよいと思います。

★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/


2014年9月3日水曜日 0:26

まさに、その通りでした。

テキストモードにしておりましたので、バイナリモードに変更したら上手くいきました。

受け取り側の変数を何とか配列型に入れる方法を考えてばかりおりましたが、そもそもの元データと変数を理解してないばかりに悩んだ結果ですね。

本当に助かりました。

また、【System.IO.Ports.SerialPort】を使用した方が良いとのアドバイスですが、その通りだと思います。VB6のプログラムをVB.NETへの転記が完了し、プログラムの;働が確認出来たら書き直す予定で御座います。

以上、本当に有難うございました。