.NETでAPI関数の使用

仕事の関係で、.NETからAPI関数のいじくり方を調べていたのでそれをちょっとまとめておきます。

とりあえず、.NETからAPI関数をいじくるには関数を宣言しなくてはいけないのですが、その宣言がやたら面倒です。

とりあえず、一例を…

[DllImport("Winmm.dll")]
private static extern uint midiOutShortMsg(uint hmo, uint dwMsg );

まぁ、こんな感じです。宣言が終われば、あとは使うだけですね。(相変わらず、いい加減な説明…)

えっと、まずは一行目のDllImportですが・・・ここには使いたいAPI関数が入っているdll名を書いてください。今回はwinmm.dllみたいですね。どの関数がどこに入っているかはmsdnライブラリでも調べれば簡単に見つかると思います。ちなみに、このDllImport属性はネームスペース「System.Runtime.InteropServices」がないと使えないようなので、ファイルの先頭部分にでも「using System.Runtime.InteropServices;」と書いておいてください。

次に関数の宣言です。外部dllの関数を宣言するので「extern」を付けてください。でもって、関数なので「static」で宣言です。アクセス修飾詞は適当で。

そうしたら、宣言したい関数と同じように引数なり、戻り値を宣言してやります…ここでもう一つ問題なのが、変数の型です。API関数というのは全てアンマネージコードなのに対して、.NETは全てマネージコードです。そのため、変数の型名が微妙に異なります。出来るだけ互換性を持った型を指定してやらなくてはなりません。ここら辺の対応表みたいなものもネットで検索すれば簡単に出てくるでしょう。

そんな感じで宣言したら、あとは普通のstatic関数として使用できます。あ〜面倒!

こんな感じで、MIDIのショートメッセージを送るプログラムを書いていました。そのコードの一部もメモっておきます。もちろん、C#用のコードです。

			  
using System;
using System.Runtime.InteropServices;

namespace MIDIPanel
{

	public class MIDIControl
	{
		private delegate void MidiOutProc( 
					IntPtr hmo, 
					UInt32 hwnd, 
					Int32 dwInstance, 
					Int32 dwParam1, 
					Int32 dwParam2);

		[DllImport("Winmm.dll", CharSet=CharSet.Auto)]
		private static extern uint midiOutGetNumDevs();
		[DllImport("Winmm.dll", CharSet=CharSet.Auto)]
		private static extern uint midiOutGetDevCaps(uint
			uDeviceID, out MIDIOUTCAPS lpMidiOutCaps, int
			cbMidiOutCaps);

		[DllImport("Winmm.dll", CharSet=CharSet.Auto)]
		private static extern uint midiOutOpen(
			ref uint lphmo,         
			Int32 uDeviceID,           
			MidiOutProc dwCallback,         
			Int32 dwCallbackInstance, 
			Int32 dwFlags             
			);
		[DllImport("Winmm.dll", CharSet=CharSet.Auto)]
		private static extern uint  midiOutShortMsg(
			uint  hmo, 
			uint  dwMsg   
			);

		[DllImport("Winmm.dll", CharSet=CharSet.Auto)]
		private static extern uint  midiOutClose(
			uint  hmo  // MIDI出力デバイスのハンドル
			);

		[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
			private struct MIDIOUTCAPS
		{
			public ushort wMid;
			public ushort wPid;
			public uint vDriverVersion;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
			public string szPname; //public char[32] szPname;
			public ushort wTechnology;
			public ushort wVoices;
			public ushort wNotes;
			public ushort wChannelMask;
			public uint dwSupport;
		}

		public int Num;

		private uint device;

		public MIDIControl()
		{
			Num = (int)midiOutGetNumDevs();
			device = 0;
		}

		public string GetMIDIDeviceName(int IDNum)
		{
			MIDIOUTCAPS moc;
			midiOutGetDevCaps((uint)IDNum, out moc, Marshal.SizeOf(typeof(MIDIOUTCAPS)));
			return moc.szPname;
		}

		public void DeviceOpen(int IDNum)
		{
			midiOutOpen(ref device, IDNum, null, 0, 0);

		}
		public void SendMessage(uint Mes)
		{
			midiOutShortMsg(device, Mes);
		}

		public void DeviceClose()
		{
			midiOutClose(device);
		}

	}
}

              

こんな感じです。色々なページを探し回って切り貼りして作ったコードなので、変数名に一貫性がありませんが、とりあえず動きます。ショートメッセージの送信と、MIDIバイスのデバイス名の取得が出来るクラスになっています。.NETでMIDIプログラムを組みたい方は参考に…

いつにも増して、今日はグダグダな日記なのでこの辺で…