MIDIポートの数を取得する
・midiOutGetNumDevsを使います。
/**** Source Code (C#) ****/ /// <summary> /// MIDI出力APIの宣言です。 /// </summary> public static class MidiOutApi { /// <summary> /// MIDI出力ポートの数を取得します。 /// </summary> [DllImport("winmm.dll", EntryPoint = "midiOutGetNumDevs")] [return: MarshalAs(UnmanagedType.U4)] public static extern uint midiOutGetNumDevs(); /* ... */ }
'**** Source Code (VB.net) ****' ''' <summary> ''' MIDI出力APIの宣言です。 ''' </summary> Public Class MidiOutApi ''' <summary> ''' MIDI出力ポートの数を取得します。 ''' </summary> <DllImport("winmm.dll", EntryPoint:="midiOutGetNumDevs")> _ Public Shared Function midiOutGetNumDevs() As <MarshalAs(UnmanagedType.U4)> UInteger End Function End Class
Windows APIを使ったことのある人にはおなじみの、マーシャリング宣言です。
省略可能なキーワードを省略すると次のようになります。
/**** Source Code (C#) ****/ public static class MidiOutApi { /// <summary> /// MIDI出力ポートの数を取得します。 /// </summary> [DllImport("winmm.dll")] public static extern uint midiOutGetNumDevs(); }
'**** Source Code (VB.net) ****' Public Class MidiOutApi ''' <summary> ''' MIDI出力ポートの数を取得します。 ''' </summary> Public Shared Function midiOutGetNumDevs() As UInteger End Function End Class
ではなぜわざわざ明示してあるのかというと、この宣言文はMSDNライブラリなりC++言語用のヘッダーファイルなりを参照して、厳密に作られた宣言であることを明示するためです。
マーシャラは細かいので、宣言を間違えていると、時々(しかも、予測不可能なタイミングで)システムなんとかエラーだとかランタイムエラーだとかすごく大仰なエラーで飛んでしまいます。
それを避けるために、わざわざ調べているわけです。(多分、戻り値がintでも動きます…が)
この関数を実際に使用するには、以下のようなソースコードを書きます。
/**** Source Code (C#) ****/ class Program { static void Main(string[] args) { Console.WriteLine(MidiOutApi.midiOutGetNumDevs()); } }
'**** Source Code (VB.net) ****' Module Program Sub Main() Console.WriteLine(MidiOutApi.midiOutGetNumDevs()) End Sub End Module
実行結果:
20
ちょっと、一般的な環境とは違うと思いますけど。
この関数は引数も取らないし、戻り値も整数なので気にならないですが、じき固定長文字列用のポインタをくれとか言い出して面倒なことになるので、マネージドのラッパーを被せてしまいたいところです。
あと関数名がC#の命名規則と違う。(参照→メソッドの名前付けのガイドライン(MSDN))
ということで、C#のラッパーを作ります。
/**** Source Code (C#) ****/ /// <summary> /// MIDI-OUTポートを抽象化するクラスです。 /// </summary> public sealed class MidiOutPortHandle //: IDisposable { /// <summary> /// MIDI出力ポートの数を取得します。 /// </summary> public static int GetPortCount() { return (int)MidiOutApi.midiOutGetNumDevs(); } /* ... */ }
'**** Source Code (VB.net) ****' ''' <summary> ''' MIDI-OUTポートを抽象化するクラスです。 ''' </summary> Public NotInheritable Class MidiOutPortHandle 'Implements IDisposable ''' <summary> ''' MIDI出力ポートの数を取得します。 ''' </summary> Public Shared Function GetPortCount() As Integer Return MidiOutApi.midiOutGetNumDevs() End Function '* ... *' End Class
クラス名がMidiOutPortではなくMidiOutPortHandleなのは将来的な理由によります。
MidiOutPortHandleの実装を説明しないうちに明かすのは野暮ですが、このプログラムコードではアンマネージドのMIDIポートの上に二層の抽象化を施そうと考えているからです。
MidiOutPortというクラス名はより上位のクラスのために予約されています。
また、このコードのように、インスタンスクラスの上に関連するstaticメソッドを実装するというコーディング手法は結構多用されます。
例えばEncoding.GetEncoding(string name)など。
ただし多用しすぎるとコードが本来の目的を逸して読みにくくなるので注意が必要です。
最終的な呼び出しは以下のようになります。
/**** Source Code (C#) ****/ class Program { static void Main(string[] args) { Console.WriteLine(MidiOutPortHandle.GetPortCount()); } }
'**** Source Code (VB.net) ****' Module Program Sub Main() Console.WriteLine(MidiOutPortHandle.GetPortCount()) End Sub End Module