構造体の内容を変数にコピーする

ホストコンピュータに固定長のデータを渡すテキストファイルを作成する場合に便利なテクニックです。
構造体の内容を変数にコピーしてPrint #ステートメントでファイルに出力することができ、コーディングの手間を省けます。

このテクニックは構造体の各要素がすべて文字型の場合のみ使用したほうが良いと思います。構造体の要素が整数型の場合など文字型以外の場合、各要素の内容が壊れる可能性があります。
これは、VBが文字型内部表現をUnicodeで持っているため、DLLに引数を渡す時に、UnicodeからANSIに変換してしまうからと思われます。(DLLの引数の型がAnyの場合でも変換されるようです)

サンプル(32bit)

'構造体コピーAPI
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Type TUHAN_SYSTEM_REC
     KUBUN          As String * 1
     HYAKATEN_ID    As String * 2
     HAGAKI_NO      As String * 12
     DEN_NO         As String * 12
     TODO_NAME      As String * 40
     TODO_KANA_SEI  As String * 10
     TODO_KANA_NEI  As String * 10
     TODO_YOU       As String * 8
     TODO_ADD1      As String * 40
     TODO_ADD2      As String * 40
     TODO_ADD3      As String * 40
     TODO_TEL1      As String * 5
     TODO_TEL2      As String * 4
     TODO_TEL3      As String * 4
     IRA_NAME       As String * 40
     IRA_KANA_SEI   As String * 10
     IRA_KANA_NEI   As String * 10
     IRA_YOU        As String * 8
     IRA_ADD1       As String * 40
     IRA_ADD2       As String * 40
     IRA_ADD3       As String * 40
     IRA_TEL1       As String * 5
     IRA_TEL2       As String * 4
     IRA_TEL3       As String * 4
     FILLER         As String * 21
End Type

Public TUHAN_SYSTEM As TUHAN_SYSTEM_REC


Private Sub EXPORT_SYORI()

       Dim sDATA As String

       'データレコード出力
       sDATA = Space(Len(TUHAN_SYSTEM))
       Call CopyMemory(ByVal sDATA, TUHAN_SYSTEM, Len(TUHAN_SYSTEM))
       Print #1, sDATA

End Sub

サンプル解説

CopyMemory関数で構造体の内容を変数 sDATA にコピーしています。

引数は次の通りです。
(引数の名前は、Declare Functionで指定したものです)

メンバー I/O 説明
Destination In コピー先の変数、または、構造体名
Source Out コピー元の変数、または、構造体名
Length In コピー元のサイズ。(バイト数)

引数を渡す場合に注意する点があります。変数の場合はByValを付けて値渡しをする必要があります。逆に、構造体の場合は参照渡しにする必要があります

また、コピー先が変数 sDATA のように可変長の場合、あらかじめ領域を確保する必要があります。
サンプルでは、sDATA = Space(Len(TUHAN_SYSTEM))で構造体のサイズ分スペースを代入しています。

また、引数の説明でも判るように、変数の内容を構造体にコピーする事も可能です。
ただし、この場合、1つ注意する点があります。
変数内に漢字が存在した場合、コピー後、漢字の入った構造体の要素の前の要素の末尾にゴミが入る場合があります。この要素は固定長の指定した長さより大きくなっており、大きくなった部分にゴミが入ります。この状態になったら、Left関数などで大きくなった部分を切り捨てる必要があります。

(一旦、ANSIに変換してLeftB関数でバイト単位に切り捨てるほうがバグの原因になりにくいのでお勧めです。切り捨て後、再びUnicodeに変換すればOKです)
(各要素は大きくなるだけで、内容は正常です)

 これは、VBが引数の内容をUnicodeからANSIに変換してDLLに渡し、DLLがメモリ(この場合は引数の内容)をコピーして、再びVBに戻りANSIからUnicodeに変換しているのですが、物が構造体だけにANSIからUnicodeの変換に漢字が入ると不具合が生じるみたいです。

また、引数DestinationやSourceは実際はポインタなので、APIで得たポインタが示す値を取得したりなど、値←→ポインタの相互変換もできます・・・。
(例えば、DEVMODE構造体の入出力に利用できたりします)


[ Window Close ]