掲示板システム
ホーム
アクセス解析
カテゴリ
ログアウト
VB.netにて、構造体の中身をString変数にコピーするには? (ID:83282)
名前
ホームページ(ブログ、Twitterなど)のURL (省略可)
本文
> 逆も、 > TEST2.strA = Mid(strValue , 1 , 1) 代入用のメソッドやプロパティ、あるいはパラメータ付きコンストラクタを用意するとか…。 > 構造体&メンバ数が沢山あるプログラムなもので・・・ メンバを配列やコレクションにして管理するとか、あるいは、CallByNameやリフレクションなどを使って、各メンバをループで処理するとか…。 > メモリコピーのような感じで、.netで実現する方法を教えていただけないでしょうか? フィールドが「値型」のみで構成されていれば、 <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _ Public Structure STRC_ABC Dim strA As Char Dim strB As Char Dim strC As Char Private Declare Ansi Sub RtlMoveMemory Lib "kernel32" _ (ByVal Destination As String, ByRef Source As STRC_ABC, ByVal Length As Integer) Public ReadOnly Property Text() As String Get Dim Size As Integer = Marshal.SizeOf(Me) Text = Space(Size) RtlMoveMemory(Text, Me, Size) End Get End Property End Structure などとしておいて、それを以下のように利用できます。 Dim ABC As STRC_ABC ABC.strA = "a"c '文字列(String)ではなく、文字(Char)を指定するために、 ABC.strB = "b"c '右辺が「"X"c」のような「文字リテラル」になっている事に注意。 ABC.strC = "c"c 'ただし、Option Strict Offの時に限っては、「"X"」のような、 '「文字列リテラル」を指定しても、コンパイルする事ができます。 Dim strValue As String = ABC.Text MessageBox.Show(strValue) しかし、フィールドに文字列が含まれている場合には、Marshal.Copyメソッドを使うにしても、RtlMoveMemory APIを使うにしても、少々面倒な手続きが必要なようです。 VB6でも、固定長ではないString型を含むユーザー定義型は、LSetステートメントによる代入ができない事になっていましたよね。 '---- VB6(このコードはエラーになります) ---- Private Type T1 'S As String * 4 S As String End Type Private Type T2 'S As String * 4 S As String End Type ---- Dim A As T1 Dim B As T2 A.S = "TEST" LSet B = A '---- VB6 ---- VB6の頃は、String型を「固定長文字列型」にしたり「Byte型の静的配列」にしたりする事で対応できたのですが、VB.NETではそれらがサポートされていません。 これはつまり、マーシャリングの為に、既存のコードに修正を加える必要がある、という事になります。 さて本題。 最初の質問では、Stringフィールドに<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=X)>を指定して固定長文字列を表されていたようですが、ByValTStr だと、Null終端文字列を意味する事になるため、期待通りの結果にはならないでしょう。 http://www.microsoft.com/japan/msdn/library/ja/cpref/html/frlrfsystemruntimeinteropservicesunmanagedtypeclasstopic.asp 》 .NET Framework の ByValTStr 型は、構造体内の C スタイルの 》 固定サイズ文字列 (char s[5] など) と同様に機能します。 》 マネージ コードでのこの動作は、Microsoft Visual Basic 6.0 の 》 動作 (終端が null でない。例: MyString As String * 5) とは 》 異なります。 で。終端Nullを含まない文字列にしたい場合には、Char配列を使う事で代用できます。 たとえば、VB6でいうところの「String * 1」のイメージにするのであれば、 <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _ Public Structure STRC_ABC <MarshalAs(UnmanagedType.ByValArray, ArraySubType:=UnmanagedType.ByValTStr, SizeConst:=1), VBFixedArray(1)> Dim strA() As Char <MarshalAs(UnmanagedType.ByValArray, ArraySubType:=UnmanagedType.ByValTStr, SizeConst:=1), VBFixedArray(1)> Dim strB() As Char <MarshalAs(UnmanagedType.ByValArray, ArraySubType:=UnmanagedType.ByValTStr, SizeConst:=1), VBFixedArray(1)> Dim strC() As Char Private Declare Ansi Sub RtlMoveMemory Lib "kernel32" _ (ByVal Destination As String, ByRef Source As STRC_ABC, ByVal Length As Integer) Public ReadOnly Property Text() As String Get Dim Size As Integer = Marshal.SizeOf(Me) Text = Space(Size) RtlMoveMemory(Text, Me, Size) End Get End Property End Structure という感じです。 ただしこの場合、フィールドの定義が As String から As Char() に変更されていますので、 ABC.strA = "a" ではなく、 ABC.strA = "a".ToCharArray() か、もしくは ABC.strA = New Char() {"b"c} などとしないと、Option Strict On時にコンパイルが通らないことになります。 メモリコピーの動作を優先させようとすると、既存コードへの影響が大きくなってしまうかも知れませんよ。 # 私自身は、.NETはさほど詳しいわけではないので、間違っているかも知れません。 # 何か問題があれば、フォローをお願いします。>識者の方
←解決時は質問者本人がここをチェックしてください。
戻る
掲示板システム
Copyright 2020 Takeshi Okamoto All Rights Reserved.