- PR -

VB.NETで文字列の構造体をバイト配列へコピーする方法

投稿者投稿内容
未記入
会議室デビュー日: 2006/08/10
投稿数: 6
投稿日時: 2006-08-10 16:13
VB.NET2005において、構造体をバイト配列へコピーする方法で
正しくコピー出来ないで困っています。

下記コードを実行すると
bdata(0)=49
bdata(1)=50
bdata(2)=0
bdata(3)=52
bdata(4)=53
bdata(5)=0
の結果になります。
望んでいる結果は
bdata(0)=49
bdata(1)=50
bdata(2)=0
bdata(3)=52
bdata(4)=53
bdata(5)=0
です。

---------------------------コード
<StructLayout _
(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure BUF
<VBFixedString(3), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=3)> Public data1 As String
<VBFixedString(3), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=3)> Public data2 As String
End Structure

Dim sendbuf As BUF
Dim bdata As Byte()
With sendbuf
.data1 = "123"
.data2 = "456"
End With
Dim size As Integer = Marshal.SizeOf(sendbuf)
Dim buffer As IntPtr = Marshal.AllocCoTaskMem(size)
Marshal.StructureToPtr(sendbuf, buffer, True)
ReDim bdata(size - 1)
Marshal.Copy(buffer, bdata, 0, size)
-------------------------------------
未記入
会議室デビュー日: 2006/08/10
投稿数: 6
投稿日時: 2006-08-10 16:15
すいませんでした。
一部誤りがありましたので訂正します。
望んでいる結果は
bdata(0)=49
bdata(1)=50
bdata(2)=51
bdata(3)=52
bdata(4)=53
bdata(5)=54
です。
未記入
会議室デビュー日: 2006/08/10
投稿数: 6
投稿日時: 2006-08-10 16:15
すいませんでした。
一部誤りがありましたので訂正します。
望んでいる結果は
bdata(0)=49
bdata(1)=50
bdata(2)=51
bdata(3)=52
bdata(4)=53
bdata(5)=54
です。
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-08-10 17:41
必ず終端文字が含まるようになっているので String じゃ無理ですね。
// 「正しくコピーできない」わけではありません。

Byte 配列にして ByValArray にして入れるときに Encoding クラス使うとか。
String のプロパティ作って、フィールドに格納するときに Encoding 施すってのはどうかなー。
未記入
会議室デビュー日: 2006/08/10
投稿数: 6
投稿日時: 2006-08-10 18:09
返事有難うございます。

>>必ず終端文字が含まるようになっているので String じゃ無理ですね。
>>// 「正しくコピーできない」わけではありません。

●Structure時での指定を変えるなどして終端文字(Null)が含まれないように
 出来ないのでしょうか。

>>Byte 配列にして ByValArray にして入れるときに Encoding クラス使うとか。
>>String のプロパティ作って、フィールドに格納するときに Encoding 施すってのはどうかなー。

●意味がいまいち理解出来ていないのですが、Encoding クラスをどのように
 使うのでしょうか。

Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-08-10 23:18
文字列が終端子を必ず含むからです(でなければ、どこで終わったらいいのかわからない)。
C 言語使いなら、1度は痛い思いをしているはずのところなので、よく分かるんですけどね。

なので、終端子を含まないようにする必要があります。それは結構簡単で、「文字列」ではなく、「文字配列」にしてやればいいわけです。

 ただし、「変数 = "123"」という使い方は、出来なくなります(手間だけど、そんなに難しくはない)。あ、プロパティ作るってか。なるほど!!
 構造体って、VB.NET では class と変わらないんですよ。


 そういえば、ASCII 7bit の範囲の文字だけを使うなら問題ないですが、それ以外の文字も使うなら、問題になるかもしれませんね。→エンコード
未記入
会議室デビュー日: 2006/08/10
投稿数: 6
投稿日時: 2006-08-11 10:49
下記コードで望んだ結果を配列にセットすることが出来ました。
とりあえず最初に望んだ結果になったのですが、構造体のメンバ数が
増えると同じような処理のコードをメンバ数分繰り返し書かないと
いけないのが難点ですが。。。

コード-------------------------------------------------------------------------
<StructLayout _
(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure BUF
<VBFixedString(3), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=3)> Public data1 As String
<VBFixedString(3), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=3)> Public data2 As String

Function Getbyte(ByVal sendbuf As BUF) As Byte()
Dim size As Integer
Dim bdatabuf As Byte()
Dim bdatabuf1 As Byte()
Dim i As Integer
Dim cnt As Integer

size = Marshal.SizeOf(sendbuf)
ReDim bdatabuf(size - 1)

cnt = 0
bdatabuf1 = Encoding.GetEncoding("SHIFT_JIS").GetByte(sendbuf.data1)
For i = 0 To UBound(bdatabuf1)
bdatabuf(cnt) = bdatabuf1(i)
cnt = cnt + 1
Next
bdatabuf1 = Encoding.GetEncoding("SHIFT_JIS").GetByte(sendbuf.data2)
For i = 0 To UBound(bdatabuf1)
bdatabuf(cnt) = bdatabuf1(i)
cnt = cnt + 1
Next
Getbyte = bdatabuf
End Function

End Structure



Dim sendbuf2 As BUF
Dim bdata2 As Byte()
With sendbuf2
.data1 = "1234"
.data2 = "456"
'.data1 = "あ3"
'.data2 = "い6"
End With
bdata2 = sendbuf2.Getbyte(sendbuf2)


Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-08-11 22:14
VB.NET とネイティブの間でどのような変換がされるのか、調べていないので不確かですが。。。

本当に大丈夫ですか?「文字列」と、「文字配列」は違います。「文字列」には、必ず終端子が入ります。サイズには、終端しも含まなければなりません。ただし、文字数には終端子は含まれません。
しかし、「文字配列」は、そもそも終端子がありません。1文字しか入らない箱が並んでいるだけですから。文字配列を文字列のように扱えるのは、配列が必ず連続したアドレスに割り振られるからです。

いま、UnmanagedType.ByValTStr, SizeConst:=3 と、文字列でサイズを3と指定していますが、このサイズには終端子が含まれなければなりません。3文字埋めてしまうと、終端子がなくなって、文字列の終わりを判別できなくなるような気がします。

スキルアップ/キャリアアップ(JOB@IT)