C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[2]: C♯ 固定長文字列について


(過去ログ 98 を表示中)

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■58733 / inTopicNo.1)  C♯ 固定長文字列について
  
□投稿者/ ポラン (3回)-(2011/04/25(Mon) 09:05:42)

分類:[C#] 


分類:[C#]

開発環境:WindowsXP SP3
言語: VisualStudio2010 C#

計測器の制御で、DLLの関係でVB6で使用した固定長文字列を
使用しないとreadコマンドが読めず困っています。

///////////
VB6の場合
DLLの定義
Declare Function viRead Lib "VISA32.DLL" Alias "#256" (ByVal vi As Long, ByVal Buffer As String,
ByVal count As Long, retCount As Long) As Long

Dim Instring As String * 256
256の固定長文字列になります。

viRead(vi, Instring, 256, x)
viRead関数のInstringが戻り値となって
文字列が返ってきます。
////////////
VB.netの場合
Imports Microsoft.VisualBasic.Compatibilityの定義

DLLの定義
Declare Function viRead Lib "VISA32.DLL" Alias "#256"(ByVal vi As Integer, ByVal Buffer As String,
ByVal count As Integer, ByRef retCount As Integer) As Integer

Dim Instring As New VB6.FixedLengthString(256)
VB6用の固定長文字列になります。

viRead(vi, Instring.Value, 256, xx)
viRead関数のInstringが戻り値となって
文字列が返ってきます。
//////////
C#の場合
using Microsoft.VisualBasic;の定義

DLLの定義
public static extern int viRead(int vi, string Buffer, int count, ref int retCount);
[DllImport("VISA32.DLL", EntryPoint = "#219", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]

[VBFixedString(256)]public string Instring;
sts = class1.viRead(vi, Instring, 256, ref x);
この定義で動作するかなと思ったのですが、Instringがnull値と
なって何も文字列が返ってきませんでした。原因を調べた所、VB6は16bitで
C#は32bitなので、この定義だと32bitの固定長文字列となって動作しないのでは?
と思っています。元のDLLを直せばそれで直るのかなと思っているのですが、
メーカー配布のDLLの為、どうやって直したらいいのか素人の為分りません。
DLLを直さずに、動作する方法があればどなたか教えて頂きたいです。

以上よろしくお願い致します。
引用返信 編集キー/
■58734 / inTopicNo.2)  Re[1]: C♯ 固定長文字列について
□投稿者/ よねKEN (689回)-(2011/04/25(Mon) 09:27:36)
> DLLの定義
> public static extern int viRead(int vi, string Buffer, int count, ref int retCount);
> [DllImport("VISA32.DLL", EntryPoint = "#219", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]

外部関数の件の引数を「string Buffer」ではなく「byte[] buffer」のようにバイト配列で宣言したらどうでしょう。

使用する側もそれに合わせて

byte[] Instring= new byte[256];
> sts = class1.viRead(vi, Instring, 256, ref x);

こんな感じで取得します。
後はEncodingクラスを使って文字列に変換すればよいかと思います。
引用返信 編集キー/
■58735 / inTopicNo.3)  Re[2]: C♯ 固定長文字列について
□投稿者/ ポラン (4回)-(2011/04/25(Mon) 10:01:33)
No58734 (よねKEN さん) に返信
>>DLLの定義
>>public static extern int viRead(int vi, string Buffer, int count, ref int retCount);
>>[DllImport("VISA32.DLL", EntryPoint = "#219", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
>
> 外部関数の件の引数を「string Buffer」ではなく「byte[] buffer」のようにバイト配列で宣言したらどうでしょう。
>
> 使用する側もそれに合わせて
>
> byte[] Instring= new byte[256];
>>sts = class1.viRead(vi, Instring, 256, ref x);
>
> こんな感じで取得します。
> 後はEncodingクラスを使って文字列に変換すればよいかと思います。
さっそく直してみた所、動作致しました
よねKEN様ご回答ありがとうございました。
解決済み
引用返信 編集キー/
■58736 / inTopicNo.4)  Re[1]: C♯ 固定長文字列について
□投稿者/ 魔界の仮面弁士 (2154回)-(2011/04/25(Mon) 10:21:05)
# 既に解決済みのようですが、折角書いたので投稿しておきます。
# 長文なので読み飛ばし推奨。(問題解決に関係のない蛇足情報が多いため)

No58733 (ポラン さん) に返信
> 計測器の制御で、DLLの関係でVB6で使用した固定長文字列を
> 使用しないとreadコマンドが読めず困っています。

まずは VB6 側のコードについて指摘。

VB6 固定長文字列は、「文字数」を制御するための物であるため、
> Dim Instring As String * 256
は、「Unicode文字列256文字分(もしくはバイナリ512バイト分)」のデータ長を意味します。

また、それを API に ByVal String 形式で渡した場合、暗黙の Unicode → ANSI 変換が入るため、
この変換が行えないようなデータが含まれていると、それらは破損(文字化け)する事になります。
その点は大丈夫でしょうか?

バイナリデータのやり取りが目的なら、Dim Instring() As Byte にしておき、
API 側は ByRef Buffer As Byte で、呼び出しを
 ReDim Instring(255)
 Call viRead(vi, Instring(0), 256, x)
としておいた方が安全かと思います。データが英数字だけの場合は String のままでも良いですが。


> Dim Instring As String * 256
> 256の固定長文字列になります。
この呼出ならば、固定長にこだわる必要は無く、
 Dim Instring As String
 Instring = = String(256, 0) 'VB6
で十分であるように思えます。

> viRead(vi, Instring, 256, x)
VB6 なので、
 viRead vi, Instring, 256, x
もしくは
 Call viRead(vi, Instring, 256, x)
ですよね?



> VB.netの場合
Microsoft.VisualBasic.Compatibility.VB6.FixedLengthString ではなく、
API 宣言を ByVal System.Text.StringBuilder にすれば処理できるかと思います。
あるいは、API 宣言を「ByVal Buffer() As Byte」にしておき、バイト配列で交換するとか。


> [VBFixedString(256)]public string Instring;
さて本題。

これらを C# で処理するのであれば、
 案1) 「byte 配列」を使って処理する。

 案2) 「StringBuilder クラス」を使って処理する。

 案3) 「fixed」で固定サイズバッファを利用する。
  http://msdn.microsoft.com/ja-jp/library/zycewsya%28VS.90%29.aspx
  http://msdn.microsoft.com/ja-jp/library/f58wzh21%28VS.90%29.aspx
あたりで如何でしょうか。(他にも方法はあるでしょうけれども)


> この定義で動作するかなと思ったのですが、Instringがnull値となって
C# において、string をはじめとする「参照型」変数の初期値は null です。
ですから呼び出し前に、
 Instring = new String('\0', 256);
などとして、必要な長さのデータで初期化しておく必要があるでしょう。

文字列バッファにデータを書き込むタイプの API に対しては、API を呼び出す前に
Instring にバッファ分のメモリを確保しておかないといけません。
この点は、VB6 でも VB.NET でも C# でも同じです。


'--- VB6 ---
Dim a As String * 256
Dim b As String

'a => バッファ確保=True バッファ長= 512
Debug.Print "a => バッファ確保="; CBool(StrPtr(a)), "バッファ長="; LenB(a)
a = String(256, 0)

'b => バッファ確保=False バッファ長= 0
Debug.Print "b => バッファ確保="; CBool(StrPtr(b)), "バッファ長="; LenB(b)

'b => バッファ確保=True バッファ長= 512
b = String(256, 0)
Debug.Print "b => バッファ確保="; CBool(StrPtr(b)), "バッファ長="; LenB(b)


> VB6は16bitでC#は32bitなので、この定義だと32bitの固定長文字列となって動作しないのでは?
少し誤解があるようです。VB6 の何が 16 bit で、C# の何が 32bit と思われていますか?

VB6 の文字列も、C# の文字列も、内部的には Unicode 文字列です。
これは、32bit 単位の数値型(.NET 的には Char 型)を並べた物に相当します。

恐らくは、
 ・VB6 の Integer 型は、16bit サイズである。
 ・VB.NET の Integer 型は、System.Int32 型の事であり、すなわち 32bit サイズである。
 ・C# の int 型は、System.Int32 型の事であり、すなわち 32bit サイズである。
という情報と混同しておられるのかと思いますが、それは全く別問題です。


なお、単純に言語バージョンと bit 数の関係を述べる場合、どちらかといえば、
動作プラットフォームの事を指すことが多いのではないかと思います。

・.NET Framework 2.0、3.0、3.5、4 に対しては、32bit 専用アプリのほか、
 32bit/64bit 両用、64bit 専用アプリにも対応する。
  ※ VB2005〜VB2010 および C# 2005〜2010。

・.NET Framework 1.x が対応するのは、32bit 環境のみ。
 ※ VB.NET 2002(VB7)、VB.NET 2003(VB7.1) および C# 2003 以下。

・VB5〜VB6 は、32bit Windows アプリケーションの開発しか行えない。

・VB4 は、16bit Windows 開発用と 32bit Windows 開発用の 2 種類の製品が存在する。

・VB2〜VB3 は、16bit 専用 Windows アプリケーションの開発しか行えない。

・VB1は、16bit Windows 用と DOS 用の 2 種類の製品が存在する。
解決済み
引用返信 編集キー/
■58742 / inTopicNo.5)  Re[2]: C♯ 固定長文字列について
□投稿者/ ポラン (5回)-(2011/04/25(Mon) 12:17:58)
No58736 (魔界の仮面弁士 さん) に返信
> # 既に解決済みのようですが、折角書いたので投稿しておきます。
> # 長文なので読み飛ばし推奨。(問題解決に関係のない蛇足情報が多いため)
>
> ■No58733 (ポラン さん) に返信
>>計測器の制御で、DLLの関係でVB6で使用した固定長文字列を
>>使用しないとreadコマンドが読めず困っています。
>
> まずは VB6 側のコードについて指摘。
>
> VB6 固定長文字列は、「文字数」を制御するための物であるため、
>>Dim Instring As String * 256
> は、「Unicode文字列256文字分(もしくはバイナリ512バイト分)」のデータ長を意味します。
>
> また、それを API に ByVal String 形式で渡した場合、暗黙の Unicode → ANSI 変換が入るため、
> この変換が行えないようなデータが含まれていると、それらは破損(文字化け)する事になります。
> その点は大丈夫でしょうか?
>
> バイナリデータのやり取りが目的なら、Dim Instring() As Byte にしておき、
> API 側は ByRef Buffer As Byte で、呼び出しを
>  ReDim Instring(255)
>  Call viRead(vi, Instring(0), 256, x)
> としておいた方が安全かと思います。データが英数字だけの場合は String のままでも良いですが。
>
>
>>Dim Instring As String * 256
>>256の固定長文字列になります。
> この呼出ならば、固定長にこだわる必要は無く、
>  Dim Instring As String
>  Instring = = String(256, 0) 'VB6
> で十分であるように思えます。
>
>>viRead(vi, Instring, 256, x)
> VB6 なので、
>  viRead vi, Instring, 256, x
> もしくは
>  Call viRead(vi, Instring, 256, x)
> ですよね?
>
>
>
>>VB.netの場合
> Microsoft.VisualBasic.Compatibility.VB6.FixedLengthString ではなく、
> API 宣言を ByVal System.Text.StringBuilder にすれば処理できるかと思います。
> あるいは、API 宣言を「ByVal Buffer() As Byte」にしておき、バイト配列で交換するとか。
>
>
>>[VBFixedString(256)]public string Instring;
> さて本題。
>
> これらを C# で処理するのであれば、
>  案1) 「byte 配列」を使って処理する。
>
>  案2) 「StringBuilder クラス」を使って処理する。
>
>  案3) 「fixed」で固定サイズバッファを利用する。
>   http://msdn.microsoft.com/ja-jp/library/zycewsya%28VS.90%29.aspx
>   http://msdn.microsoft.com/ja-jp/library/f58wzh21%28VS.90%29.aspx
> あたりで如何でしょうか。(他にも方法はあるでしょうけれども)
>
>
>>この定義で動作するかなと思ったのですが、Instringがnull値となって
> C# において、string をはじめとする「参照型」変数の初期値は null です。
> ですから呼び出し前に、
>  Instring = new String('\0', 256);
> などとして、必要な長さのデータで初期化しておく必要があるでしょう。
>
> 文字列バッファにデータを書き込むタイプの API に対しては、API を呼び出す前に
> Instring にバッファ分のメモリを確保しておかないといけません。
> この点は、VB6 でも VB.NET でも C# でも同じです。
>
>
> '--- VB6 ---
> Dim a As String * 256
> Dim b As String
>
> 'a => バッファ確保=True バッファ長= 512
> Debug.Print "a => バッファ確保="; CBool(StrPtr(a)), "バッファ長="; LenB(a)
> a = String(256, 0)
>
> 'b => バッファ確保=False バッファ長= 0
> Debug.Print "b => バッファ確保="; CBool(StrPtr(b)), "バッファ長="; LenB(b)
>
> 'b => バッファ確保=True バッファ長= 512
> b = String(256, 0)
> Debug.Print "b => バッファ確保="; CBool(StrPtr(b)), "バッファ長="; LenB(b)
>
>
>>VB6は16bitでC#は32bitなので、この定義だと32bitの固定長文字列となって動作しないのでは?
> 少し誤解があるようです。VB6 の何が 16 bit で、C# の何が 32bit と思われていますか?
>
> VB6 の文字列も、C# の文字列も、内部的には Unicode 文字列です。
> これは、32bit 単位の数値型(.NET 的には Char 型)を並べた物に相当します。
>
> 恐らくは、
>  ・VB6 の Integer 型は、16bit サイズである。
>  ・VB.NET の Integer 型は、System.Int32 型の事であり、すなわち 32bit サイズである。
>  ・C# の int 型は、System.Int32 型の事であり、すなわち 32bit サイズである。
> という情報と混同しておられるのかと思いますが、それは全く別問題です。
>
>
> なお、単純に言語バージョンと bit 数の関係を述べる場合、どちらかといえば、
> 動作プラットフォームの事を指すことが多いのではないかと思います。
>
> ・.NET Framework 2.0、3.0、3.5、4 に対しては、32bit 専用アプリのほか、
>  32bit/64bit 両用、64bit 専用アプリにも対応する。
>   ※ VB2005〜VB2010 および C# 2005〜2010。
>
> ・.NET Framework 1.x が対応するのは、32bit 環境のみ。
>  ※ VB.NET 2002(VB7)、VB.NET 2003(VB7.1) および C# 2003 以下。
>
> ・VB5〜VB6 は、32bit Windows アプリケーションの開発しか行えない。
>
> ・VB4 は、16bit Windows 開発用と 32bit Windows 開発用の 2 種類の製品が存在する。
>
> ・VB2〜VB3 は、16bit 専用 Windows アプリケーションの開発しか行えない。
>
> ・VB1は、16bit Windows 用と DOS 用の 2 種類の製品が存在する。
何で動作しなかったのか原因がよく分かりました。
貴重なご回答ありがとうございます。
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -