• 検索結果がありません。

構造体

N/A
N/A
Protected

Academic year: 2021

シェア "構造体"

Copied!
8
0
0

読み込み中.... (全文を見る)

全文

(1)

構造体を取り扱うには、System.Runtime.InteropServices 名前空間をインポートして置くと便利で有 る。 Visual Basic Imports System.Runtime.InteropServices C# using System.Runtime.InteropServices; ■ ユーザー定義型(Type)と構造体(Structure)

Visual Basic 6.0 のユーザー定義型(Type)を Visual Basic.NET 以降の構造体(Structure)に移行す る時に問題に成るのが、配列と固定長文字列の要素で有る。

Visual Basic 6.0 Private Type MyType

ItemArray(5) As Integer ItemString As String * 100 End Type

上記のユーザー定義型をアップグレードすると、下記の様な構造体に成る。 Visual Basic

Private Structure MyType Dim ItemArray() As Short

<VBFixedString(100), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=100)> Dim ItemString As String

Public Sub Initialize() ReDim ItemArray(5) End Sub End Structure 此の構造体には、配列の要素数を初期化する為のユーザー定義関数(Initialize)が含まれて居り、此の 関数を利用して配列の要素を初期化するように TODO コメントも追加されるので、此のコメントを参 考に、配列の要素数を初期化する。 亦、固定長文字列に付いては、可変長文字列に変更されるが、固定配列やマーシャリングの為の属性が 追加されて居るので、固定長文字列の様に利用する事が出来る。

※ Visual Basic の文字列は、既定では可変長で有る。固定長文字列を必要とする Visual Basic のファ イル入出力関数(FileGet や FilePut 等)を使う時には、VBFixedStringAttribute 属性を使用する。 此の属性は、此等の関数への情報提供の為の属性で、可変長の文字列を固定長の文字列に変換する 為には使用出来ない。従って、此の属性に依って文字列自身の実際の長さが変更される事は無い点 に注意を要する。

(2)

■ System.Runtime.InteropServices.StructLayout 属性 System.Runtime.InteropServices.StructLayout 属性を使用すると、構造体のメモリ内での配置をカス タマイズする事が出来る。例えば、StructLayout(LayoutKind.Explicit)属性と FieldOffset 属性を使用 すると、C/C++の共用体と呼ばれる物を作成する事が出来る。 下記のコードセグメントでは、構造体Test1 の総ての要素(フィールド)がメモリ内の同じ場所で開始 される。 Visual Basic <StructLayout(LayoutKind.Explicit)> _

Private Structure Test1

<FieldOffset(0)> Dim I As Integer <FieldOffset(0)> Dim D As Double <FieldOffset(0)> Dim C As Char <FieldOffset(0)> Dim B As Byte End Structure

C# [StructLayout(LayoutKind.Explicit)]

private struct Test1 { [FieldOffset(0)] public int i; [FieldOffset(0)] public double d; [FieldOffset(0)] public char c; [FieldOffset(0)] public byte b; } 0 1 2 3 4 5 6 7 int i double d char c byte b 要素(フィールド)が別の明示的に設定された場所から開始される別の例を下記に示す。 Visual Basic <StructLayout(LayoutKind.Explicit)> _ Private Structure Test2

<FieldOffset(0)> Dim L As Long <FieldOffset(0)> Dim I1 As Integer <FieldOffset(4)> Dim I2 As Integer <FieldOffset(8)> Dim D As Double <FieldOffset(12)> Dim C As Char <FieldOffset(14)> Dim B As Byte End Structure

(3)

C# [StructLayout(LayoutKind.Explicit)]

private struct Test2 {

[FieldOffset(0)] public long l; [FieldOffset(0)] public int i1; [FieldOffset(4)] public int i2; [FieldOffset(8)] public double d; [FieldOffset(12)] public char c; [FieldOffset(14)] public byte b; } 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 long l double d

int i1 int i2 char c byte b

2 個の int 要素の i1 と i2 は、long 要素の l と同じメモリ位置を共有する。此の様な構造体レイアウトの 制御は、プラットフォーム呼出の時に便利で有る。 LayoutKind 列挙型 Auto ランタイムは、アンマネージメモリ内のオブジェクトのメンバに対して適切なレイア ウトを自動的に選択する。此の列挙体メンバで定義されたオブジェクトは、マネージ コードの外に公開出来ない。公開しようとすると、例外が生成される。 Explicit アンマネージメモリ内に有るオブジェクトの各メンバの正確な位置は、明示的に制御 される。各メンバはFieldOffsetAttribute 属性を使用して、其の型内のフィールドの 位置を指定する必要が有る。 Sequential オブジェクトのメンバは、アンマネージメモリにエクスポートする時に表示される順 番に従ってレイアウトされる。メンバは、StructLayoutAttribute.Pack で指定したパ ッキングに従ってレイアウトされる。メンバは非連続する事が出来る。 Visual Basic <StructLayout(LayoutKind.Sequential)> _

Public Structure Point Public x As Integer Public y As Integer End Structure 'Point

<StructLayout(LayoutKind.Explicit)> _ Public Structure Rect

(4)

<FieldOffset(4)> Public top As Integer <FieldOffset(8)> Public right As Integer <FieldOffset(12)> Public bottom As Integer End Structure 'Rect

C# [StructLayout(LayoutKind.Sequential)]

public struct Point {

public int x; public int y; }

[StructLayout(LayoutKind.Explicit)] public struct Rect

{

[FieldOffset(0)] public int left; [FieldOffset(4)] public int top; [FieldOffset(8)] public int right; [FieldOffset(12)] public int bottom; }

C++ [StructLayout(LayoutKind::Sequential)]

value struct Point { public: int x; int y; }; [StructLayout(LayoutKind::Explicit)] value struct Rect

{ public: [FieldOffset(0)] int left; [FieldOffset(4)] int top; [FieldOffset(8)] int right; [FieldOffset(12)] int bottom; };

(5)

■ MarshalAsAttribute クラス

Marshal とは、プログラミング用語では、或るプログラムで利用されるデータ形式を、異なるプログラ ムで利用可能な形式に変換する事を謂い、此のクラスは、マネージコードとアンマネージコードとの間 のデータのマーシャリング方法を示す。

メンバー名 説明

AnsiBStr 長さを示すプレフィックスを付けた&1; バイトの ANSI 文字列。此のメンバーは String データ型で使用出来る。

AsAny 実行時にオブジェクトの型を確認し、其の型としてオブジェクトをマーシャリングす

る動的な型。此のメンバーは、プラットフォーム呼出メソッドに而巳有効で有る。 Bool 4 バイトの Boolean 値(true != 0、false = 0)。此れは Win32 BOOL 型で有る。 BStr 長さを示すプリフィックスを付けた&2;バイトの Unicode 文字列。此のメンバー(COM

の既定の文字列)は、String データ型で使用出来る。

ByValArray MarshalAsAttribute.Value プロパティを ByValArray に設定した場合、SizeConst フ ィールドは、配列の要素数を示す様に設定する必要が有る。ArraySubType フィール ドには、文字列型を区別する必要が 有る場合に、オプションとして配列要素 の UnmanagedType を格納出来る。此の UnmanagedType は、要素が構造体にフィール ドとして定義されて居る配列で而巳使用出来る。 ByValTStr 構造体に定義されて居るインライン固定長文字配列で使用する。ByValTStr で使用す る 文 字 型 は 、 格 納 さ れ る 構 造 体 に 適 用 す る System.Runtime.InteropServices. StructLayoutAttribute 属性の引数 System.Runtime.InteropServices.CharSet に依 って決定される。配列のサイズを示す場合は、常に MarshalAsAttribute.SizeConst フィールドを使用する。

Currency 通貨型。10 進値を Decimal ではなく、COM 通貨型としてマーシャリングする為に、 System.Decimal で使用する。 CustomMar shaler MarshalAsAttribute.MarshalType 又は MarshalAsAttribute.MarshalTypeRef フィ ー ル ド と 共 に 使 用 す る 場 合 に 、 カ ス タ ム マ ー シ ャ ラ ー ク ラ ス を 指 定 す る 。 MarshalAsAttribute.MarshalCookie フィールドは、カスタムマーシャラーに追加の 情報を渡す為に使用出来る。此のメンバーは任意の参照型で使用出来る。 Error I4 又は U4 に関連付けられたネイティブな型。此の型に依り、パラメーターはエクス ポート先のタイプライブラリにHRESULT としてエクスポートされる。 FunctionPtr C スタイルの関数ポインターとして使用出来る整数値。此のメンバーは、Delegate デ ータ型又はDelegate から継承した型で使用出来る。

HString Windows ランタイム文字列。此のメンバーは System.String データ型で使用出来る。 I1 1 バイト符号付き整数。此のメンバーを使用すると、Boolean 値を 1 バイトの C スタ

イルbool(true = 1、false = 0)に変換出来る。

I2 2 バイト符号付き整数。

I4 4 バイト符号付き整数。

I8 8 バイト符号付き整数。

IDispatch COM の IDispatch ポインター(Microsoft Visual Basic 6.0 では Object)。

IInspectable Windows ランタイムインターフェイスポインター。此のメンバーは Object データ型 で使用出来る。

Interface COM インターフェイスポインター。インターフェイスの Guid は、クラスメタデータ から取得する。インターフェイス型を直接指定する場合、又は、クラスに適用する場 合は既定のインターフェイス型を指定する場合に、此のメンバーを使用する。此のメ ンバーは、Object データ型に適用すると、UnmanagedType.IUnknown と同じ動作を

(6)

生成する。

IUnknown COM IUnknown ポインター。此のメンバーは Object データ型で使用出来る。 LPArray C スタイル配列の最初の要素へのポインター。マネージコードからアンマネージコー ドにマーシャリングする場合、配列長はマネージ配列長に依って決定される。アンマ ネ ー ジ コ ー ド か ら マ ネ ー ジ コ ー ド に マ ー シ ャ リ ン グ す る 場 合 、 配 列 の 長 さ は MarshalAsAttribute.SizeConst フィールドと MarshalAsAttribute.SizeParamIndex フィールドに依って決まる。文字列の型を区別する必要が有る場合は、配列内の要素 のアンマネージ型も考慮される。

LPStr 終端がnull の&1;バイトの ANSI 文字列。此のメンバーは、System.String データ型 及びSystem.Text.StringBuilder データ型で使用出来る。 LPStruct マネージ書式指定クラスをマーシャリングする時に使用するC スタイル構造体へのポ インター。此のメンバーは、プラットフォーム呼出メソッドに而巳有効で有る。 LPTStr プラットフォームに依存する文字列。Windows 98 では ANSI、Windows NT と Windows XP では Unicode。型 LPTStr の文字列のエクスポートがサポートされて居 ない為、此の値は COM 相互運用ではサポートされず、プラットフォーム呼出而巳で サポートされる。 LPUTF8Str UTF-8 でエンコードされた文字列へのポインター。 LPWStr 終端がnull の 2 バイトの Unicode 文字列。 R4 4 バイト浮動小数点数。 R8 8 バイトの浮動小数点数。 SafeArray SafeArray は、関連付けられた配列データの型、ランク、及び、境界を格納する自己 記述型の配列で有る。MarshalAsAttribute.SafeArraySubType フィールドと併せて 此のメンバーを使用する事に依って、既定の要素の型をオーバーライド出来る。 Struct マネージ書式指定クラスと値型をマーシャリングする為に使用するVARIANT。 SysInt プラットフォーム依存、符号付き整数:32 ビット Windows では 4 バイト、64 ビット Windows では 8 バイト。 SysUInt プラットフォーム依存、符号無し整数:32 ビット Windows では 4 バイト、64 ビット Windows では 8 バイト。 TBStr 長さを示すプレフィックスを付けた、プラットフォームに依存する char 文字列。 Windows 98 では ANSI、Windows NT では Unicode。此の BSTR に似たメンバーを 使用する事は殆ど無い。

U1 1 バイト符号無し整数。

U2 2 バイト符号無し整数。

U4 4 バイト符号無し整数。

U8 8 バイト符号無し整数。

VariantBool 2 バイトの OLE 定義 VARIANT_BOOL 型(true = -1、false = 0)。

VBByRefStr Visual Basic で、アンマネージコードの文字列を変更し、結果をマネージコードに反 映出来る様にする値。此の値は、プラットフォーム呼び出しで而巳サポートされる。 Declare 文の引数型を変換する MarshalAs 属性

Visual Basic.NET 以降では、.NET Framework の幅広いクラスライブラリにアクセス出来る為、Visual Basic 6.0 と異なり、Win32 API を呼び出す Declare 文を使用する機会は減少したのではないかと思う。 しかし、Win32 API を呼び出す機会がゼロに成った訳ではなく、依然として Declare 文は存在して居る。 此の時、問題に成るのが、文字列等のデータ型がVisual Basic.NET 以降と Win32 API で互換性が全く 無い事で有る。Visual Basic.NET 以降の文字列は、System.String クラスの文字列クラスに依り表現さ

(7)

れるが、Win32 API では文字型の配列として表現される。此の相違を乗り越えるには、API 呼び出し時 に適切なデータ型の変換が必要と成る。此の時の変換方法を指定する手段として、MarshalAs 属性が使 用される。以下は、実際にMarshalAs 属性を使用したサンプルプログラムで有る。

1 Imports System.Runtime.InteropServices 2

3 Public Class Form1

4 Inherits System.Windows.Forms.Form 5

6 …Windows フォーム デザイナで生成されたコード… 7

8 Declare Auto Sub MessageBox Lib "user32.dll" ( _ 9 ByVal hWnd As Integer, _

10 <MarshalAs(UnmanagedType.LPTStr)> ByVal lpText As String, _ 11 <MarshalAs(UnmanagedType.LPTStr)> ByVal lpCaption As String, _ 12 ByVal uType As Integer)

13

14 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles MyBase.Load

15 MessageBox(0, "Hello!", "Sample Program", 0) 16 End Sub

17 End Class

此処で注目す可き点は、8~12 行目の Declare 文の中で使用されて居る MarshalAs 属性で有る。10 行 目と11 行目の文字列は、其の儘 Win32 API に渡す事が出来ないので、変換する必要が有る。其処で、 MarshalAs 属 性 は 其 の 必 要 性 を 指 定 し て 居 る 。 具 体 的 に 何 ん な デ ー タ 型 に 変 換 す る か は 、 UnmanagedType 列挙型の値で指定して居る。MarshalAs 属性と UnmanagedType 列挙型は、 System.Runtime.InteropServices 名前空間に属して居るので、1 行目の Imports 文で此の名前空間を 指定して居る。

扨て、Win32 API 呼び出し時の文字列に関する今一つの問題は、Win32 API には文字コードの相違に 依って同じ機能を持ったAPI が実際には 2 つ存在して居る場合が有る事だ。詰り、其の 2 つの孰れを 呼び出すかの明示的な指定と、孰れの文字コードを指定して引数を変換させるかと謂う指定が必要とさ れる。上記のサンプルプログラムの場合、Declare キーワードの次の Auto キーワードが、OS の種類に 応じて、自動的に2 つの Win32 API の中から選択する事を指定して居る。Windows 9X 系では ANSI 系を、Windows NT 系では Unicode 系の API が呼ばれる事に成ると思う。引数の変換に指定した UnmanagedType.LPTStr と謂う値は、状況に応じて適切な文字コードを選択すると謂う機能を持つ。 併し、自動判定に頼らず、明示的に指定する事も出来る。以下は、明示的にUnicode 系の Win32 API を選ぶ様に記述したソースで有る。

1 Imports System.Runtime.InteropServices 2

3 Public Class Form1

4 Inherits System.Windows.Forms.Form 5

6 …Windows フォーム デザイナで生成されたコード… 7

(8)

8 Declare Auto Sub MessageBoxW Lib "user32.dll" ( _ 9 ByVal hWnd As Integer, _

10 <MarshalAs(UnmanagedType.LPWStr)> ByVal lpText As String, _ 11 <MarshalAs(UnmanagedType.LPWStr)> ByVal lpCaption As String, _ 12 ByVal uType As Integer)

13

14 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles MyBase.Load

15 MessageBoxW(0, "Hello!", "Sample Program", 0) 16 End Sub

17 End Class

ソースコードの変更点は、2 つ有る。1 つは、8 行目のメソッド名を MessageBox から MessageBoxW に変更し、Unicode 系の MessageBox API の本当の名前を指定した事だ。今 1 つは、10~11 行目の MarshalAs 属性で、Unicode 文字列を意味する UnmanagedType.LPWStr と謂う値を指定した事で有 る。猶、謂う迄も無く、メソッドの名前はDeclare 文の Alias キーワードを活用すれば変更可能なので、 MessageBox と謂う名前で呼び出す様にも出来る。 逆に、ANSI 系(日本ではシフト JIS)を用いて文字列を受け渡す様に変更したサンプルプログラムを 下記に示す。 1 Imports System.Runtime.InteropServices 2

3 Public Class Form1

4 Inherits System.Windows.Forms.Form 5

6 …Windows フォーム デザイナで生成されたコード… 7

8 Declare Auto Sub MessageBoxA Lib "user32.dll" ( _ 9 ByVal hWnd As Integer, _

10 <MarshalAs(UnmanagedType.LPStr)> ByVal lpText As String, _ 11 <MarshalAs(UnmanagedType.LPStr)> ByVal lpCaption As String, _ 12 ByVal uType As Integer)

13

14 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles MyBase.Load

15 MessageBoxA(0, "Hello!", "Sample Program", 0) 16 End Sub

17 End Class

此処では、Win32 API の名前は ANSI 系の Win32 API としての本名で有る MessageBoxA に変更し、 変換するデータ型をUnmanagedType.LPStr として居る。UnmanagedType.LPStr は ANSI 系の文字 列を示す値で有る。

参照

関連したドキュメント

Moreover, he was able to establish in [5] an optimal general inequality for sub- manifolds in real space forms which involves his δ-invariants and the main ex- trinsic

Altun, “Fixed point theorems for generalized weakly contractive condition in ordered metric spaces,” Fixed Point Theory and Applications, vol. Altun, “A common fixed point theorem

A contact manifold is called sub- critical Stein-fillable if it is the boundary of some subcritical Stein domain and its contact structure is the corresponding CR–structure, ie,

The reader is referred to [4, 5, 10, 24, 30] for the study on the spatial spreading speeds and traveling wave solutions for KPP-type one species lattice equations in homogeneous

F igueiredo , Positive solution for a class of p&amp;q-singular elliptic equation, Nonlinear Anal.. Real

Keywords and Phrases: spheres, ordered configuration spaces, sub- space arrangements, integral cohomology algebra, fibration, Serre spectral sequence..

Products̲A Products̲B Products̲C Company AHTS PSV FPSO Drill  Ship Semi-

The system clock that clocks the microcontroller, as well as peripheral clocks, can be selected from one of the following clock sources: the crystal oscillator, an internal high