英创嵌入式ARM9主板采用微软的Windows CE操作系统,可以采用eVC或者VS2005进行应用开发。C#作为一种简单易用的编程语言工具,由于其在结构构建和API界面上的优势,受到广大客户的喜爱,并为很多用户所选用。为了让广大选用C#的用户能够方便快捷地完成应用开发,英创提供了一些C#的应用例程。一些例程我们已经提供了一些说明文档,发表在英创网站上,它们是:
·基于WINCE平台C#编程要点之一
一、文件的删除和复制
二、获取存储设备的大小信息
三、重启系统函数
四、隐藏/显示Windows任务栏
·基于WINCE平台C#编程要点之二
一、在英创ARM9嵌入式主板上实现GPRS拨号上网
二、使用TcpClient和TcpListener两个类实现网络数据传输
·使用C#进行CAN总线编程—基于WINCE平台C#编程要点之三
·CAN接口COM组件在C#语言中的使用
·SQL CE数据库的C#编程
·C#使用COM组件接口操作精简ISA总线
·C#使用COM组件接口进行串口操作
·C#调用COM组件的效率分析
英创不停地根据客户的需求添加相应的应用例程,本文将对下面两个新的要点进行浅析说明(光盘上均有相关例程):
·使用C#播放MP3或WAV音频文件
·如何定义和使用键盘热键
一、使用C#播放MP3或WAV音频文件
英创的EM9000和EM9161等嵌入式工控主板进行音频硬件扩展后,可以支持音频的播放,如果客户要在应用产品中播放MP3和WAV等音频文件,我们的例程采用了著名的第三方音频动态链接库fmodce.dll,客户可以按照如下方法进行使用:
首先,可以在应用工程中创建一个新的音频类文件,如sound.cs,在这个类文件里定义一个音频类,对fmodce.dll的音频函数进行DllImport定义,以便在应用程序中可以调用:
public static IntPtr GetStream(string filename) //获得音频文件的IntPtr
{
byte[] filenamebytes = System.Text.Encoding.Default.GetBytes(filename + null);
GCHandle hfile = GCHandle.Alloc(filenamebytes, GCHandleType.Pinned);
if (Environment.Version.Major == 1) return new IntPtr(hfile.AddrOfPinnedObject().ToInt32() + 4);
else return hfile.AddrOfPinnedObject();
}
[DllImport('fmodce.dll', EntryPoint = 'FSOUND_Init', SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]
public static extern bool Init(int mixrate, int maxsoftwarechannels, int flags); //初始化
[DllImport('fmodce.dll', EntryPoint = 'FSOUND_Stream_GetLength', SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]
public static extern int GetLength(IntPtr fstream); //获得流媒体的长度
[DllImport('fmodce.dll', EntryPoint = 'FSOUND_Stream_GetPosition', SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]
public static extern UInt32 GetPosition(IntPtr fstream); //获得流媒体当前播放位置
[DllImport('fmodce.dll', EntryPoint = 'FSOUND_Stream_Open', SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]
public static extern IntPtr Open(IntPtr data, int mode, int offset, int length); //打开音频文件
[DllImport('fmodce.dll', EntryPoint = 'FSOUND_Stream_Play', SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]
public static extern int Play(int channel, IntPtr fstream); //播放音频文件
[DllImport('fmodce.dll', EntryPoint = 'FSOUND_Stream_SetPosition', SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]
public static extern bool SetPosition(IntPtr fstream, UInt32 position); //定位音频文件播放位置
[DllImport('fmodce.dll', EntryPoint = 'FSOUND_Stream_Stop', SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]
public static extern bool Stop(IntPtr fstream); //停止播放
[DllImport('fmodce.dll', EntryPoint = 'FSOUND_Close', SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]
public static extern void Close(); //关闭音频文件
[DllImport('coredll.dll', SetLastError = true)]
public static extern int SetSystemPowerState(string psState, int StateFlags, int Options);
const int POWER_FORCE = 0x1000;
const int POWER_STATE_ON = 0x10000;
有了这些方便易用的音频函数,而后就可以在应用程序里面自由操作音频文件了。比如,播放一首songmother.mp3歌曲:
string currentSoundTrack = @'\NandFlash\songmother.mp3';
Sound.Init(44100, 16, 0); //初始化为44.1kHz
IntPtr soundStream = Sound.GetStream(currentSoundTrack);
IntPtr soundHandle = Sound.Open(soundStream, 16 | 32 | 256, 0, 0);
Sound.Play(0, soundHandle);
二、如何定义和使用键盘热键
在客户的应用开发中,很多终端设备是使用小键盘相应热键来执行相应的应用操作的。WinCE操作系统有很完善的消息传递机制,我们提供了一个热键例程来说明这个过程。
首先,可以在应用工程中创建一个新的MessageWindow类文件,如MyMessageWindow.cs,以便监视键盘操作并作出实时响应:
class MyMessageWindow : MessageWindow
{
private Form1 msgform = null;
//注意,程序的主窗体名称是Form1,所以在此定义一个msgform的Form1以便接收传递的消息
//下面是构造函数,注意在Form1.cs是通过
//keyUsage = new MyMessageWindow(this);彼此建立关联的
public MyMessageWindow(Form1 msgform)
{
this.msgform = msgform;
}
protected override void WndProc(ref Message m)//监视Windows消息
{
const int WM_HOTKEY = 0x0312; //如果m.Msg的值为0x0312那么表示用户按下了热键
switch (m.Msg)
{
case WM_HOTKEY:
Form1.ProcessHotkey(m); //按下热键时调用Form1主窗体的ProcessHotkey()函数
break;
}
base.WndProc(ref m); //将系统消息传递自父类的WndProc
}
}
在主窗体需要对Win32 API热键函数进行声明:
[DllImport('coredll.dll')] //定义一个系统范围的热键。
public static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, Keys vk);
[DllImport('coredll.dll')] //在系统中注消热键。
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
//下面的fsModifoers:定义为了产生WM_HOTKEY消息而必须与由nVirtKey参数定义的键一起按下的键。
public enum KeyModifiers
{
None = 0, //该键不按下
Alt = 1, //该键为ALT键
Control = 2, //该键为CTL键
Shift = 4, //该键为Shift键
Windows = 8 //该键为任意Windows键
}
在主窗体函数中定义热键:
public Form1()
{
InitializeComponent();
keyUsage = new MyMessageWindow(this);
//通过构造函数中参数this的传递,主窗体被传入MessageWindow中,
//主窗体的消息循环按照新的消息循环进行
RegisterHotKey(keyUsage.Hwnd, 100, 0, Keys.D1);
// 定义热键数字键'1',请注意句柄是keyUsage.Hwd(而不是Handle)
RegisterHotKey(keyUsage.Hwnd, 200, 0, Keys.D2); // 定义热键数字键'2'
RegisterHotKey(keyUsage.Hwnd, 300, 0, Keys.D3); // 定义热键数字键'3'
RegisterHotKey(keyUsage.Hwnd, 400, 0, Keys.D4); // 定义热键数字键'4'
}
接收MyMessageWindow传递过来的热键消息,并作进一步处理的函数:
public static void ProcessHotkey(Message m)
{
IntPtr id = m.WParam; //IntPtr用于表示指针或句柄的平台特定类型
string sid = id.ToString();
switch (sid)
{
case '100': //按下了热键'1',执行action1()函数
{
action1();
break;
}
case '200': //按下了热键'2',执行action2()函数
{
action2();
break;
}
case '300': //按下了热键'3',执行action3()函数
{
action3();
break;
}
case '400': //按下了热键'4',执行action4()函数
{
action4();
break;
}
}
}
那么接下来,用户只需要在action函数里面添加自己需要进行的操作即可了。