Windows Mobile:实现 Kiosk 模式
Windows Mobile:实现 kiosk 模式
引言
Windows Mobile 是一个出色的生产力设备。但默认情况下,设备允许访问所有功能(电子邮件、联系人等),在特定场景下,您可能希望限制最终用户对其中某些功能的访问。
您将有两个选择:
- 集成到标准 Shell 中
- 自定义系统为 Kiosk 模式
我将重点介绍第二种选择。为了将系统设置为 Kiosk 模式,我们将不得不:
- 编写一个具有屏幕的应用程序,该屏幕将像“Today”屏幕一样工作。
- 控制硬件按钮以限制对 Windows Mobile 功能的访问。
- 当然,还要让应用程序在启动时运行。
- 这是一个不完整的列表……
背景
我不会专注于 Compact Framework 开发和操作系统底层库的交互。但请记住 .NET Compact Framework 架构。
- 框架
- 公共语言运行时
- Windows CE
这样您就能理解为什么我们引用 microsoft.windowsce.forms
来进行底层功能调用。
我还使用了 OpenNETCF www.openNETCF.com 来读取/写入注册表。该库在其网站上已得到全面解释。
Using the Code
我们的第一个任务是使用 Visual Studio 创建一个新的 Smart Device 项目。如引言中所述,我们将设置默认窗体 Form1.cs 的属性,以创建一个类似“Today”的屏幕。您可以通过属性窗口或代码来完成。
public frmKiosk()
{
InitializeComponent();
ControlBox = false;
FormBorderStyle = FormBorderStyle.None;
MaximizeBox = false;
MinimizeBox = false;
WindowState = FormWindowState.Maximized;
}
现在,我们将不得不控制硬件按钮。这是通过 Microsoft.WindowsCE.Form.MessageWindows
来完成的。此类允许我们拦截 Windows 消息并决定如何处理它们(内部例程、向其他类引发事件,或者……什么都不做)。这将允许我们拦截由硬件按钮发送的消息,并简单地决定不响应它们!
逻辑非常简单:
- 创建一个继承自
MessageWindows
的类。重写WndProc
方法来捕获窗口消息并实现我们自己的业务逻辑。我们将仅拦截HOTKEY
消息,但相同的代码也可用于处理所有类型的窗口消息(完整列表可在 http:\\www.pinvoke.net 上找到)。 - 取消注册硬件按钮:默认情况下,硬件按钮引发的消息由默认进程处理。
- 注册硬件按钮:硬件按钮引发的消息将由我们的自定义
MessageWindows
处理。
我们的自定义 MessageWindows
的代码将如下所示:
public class internalMessageWindow : MessageWindow
{
// Which message type ?
public const int WM_HOTKEY = 0x0312;
Form referedForm;
public internalMessageWindow(Form referedForm)
{
this.referedForm = referedForm;
}
protected override void WndProc(ref Message msg)
{
switch (msg.Msg)
{
case WM_HOTKEY:
// Do no reply to this key ...
return;
}
base.WndProc(ref msg);
}
}
现在,我们需要将我们的窗体与自定义的 WindowsMessage
关联起来。
FormCode
{
internalMessageWindow messageWindow;
public Form Constructor()
{
this.messageWindow = new internalMessageWindow(this);
}
}
并使用 coredll.dll 中的 UnregisterFunc1
和 RegisterRecordKey
来取消注册/注册硬件按钮(有关签名详细信息,请参阅 http:\\www.pinvoke.net)。
FormCode
{
public Form Constructor()
{
...
RegisterHKeys.RegisterRecordKey(this.messageWindow.Hwnd);
}
}
public class RegisterHKeys
{
[DllImport("coredll.dll", SetLastError = true)]
public static extern bool RegisterHotKey
...
and
private static extern bool UnregisterFunc1
...
public static void RegisterRecordKey(IntPtr hWnd)
{
UnregisterFunc1(KeyModifiers.Windows, (int)KeysHardware.Hardware1);
RegisterHotKey(hWnd, (int)KeysHardware.Hardware1,
KeyModifiers.Windows, (int)KeysHardware.Hardware1);
// Repeat for every single hardware button you wan to handle
}
}
现在,我们需要强制我们的应用程序在每次 Windows Mobile 启动时都运行。这可以通过 coredll.dll 库的 CeRunAppAtEvent
函数来实现。此函数允许将应用程序链接到设备的特定事件。在我们的上下文中,我们将应用程序链接到 Wakeup
事件。这意味着每次设备启动时,都会引发 Wakeup
事件,并且由于我们将应用程序与此事件链接,我们的应用程序将启动。
要将应用程序链接到事件,我们将使用以下代码:
Win32.CeRunAppAtEvent(_kioskName, NotificationEvent.Wakeup);
我们将使用以下代码来“解除”应用程序/事件的链接:
Win32.CeRunAppAtEvent(_kioskName, NotificationEvent.None);
因此,现在我们有了一个启动页面,它会在设备启动时出现。我们还捕获了按钮事件以禁用硬件交互。最后一步是允许最终用户启动特定应用程序,并等待该应用程序关闭后再返回我们的启动页面。
这是一个相当简单的步骤,使用 ProcessStartInfo
类。这将允许我们在新进程中启动一个应用程序,并将当前应用程序置于等待状态,等待特定进程退出。
要启动新进程,我们将使用以下代码,它将返回进程句柄:
private static Process LaunchApp(string filename)
{
ProcessStartInfo s = new ProcessStartInfo();
s.FileName = filename;
s.UseShellExecute = true;
return Process.Start(s);
}
我们只需添加例程来启动应用程序,等待进程退出,使用此代码:
private void but_Click(object sender, EventArgs e)
{
this.Hide();
Process ela = LaunchApp(application2);
ela.WaitForExit();
this.Show();
}
需要注意的事项:
- 未处理设备的硬重置。进行硬重置将取消应用程序与
Wakeup
事件的订阅。 - 此解决方案不可移植!窗体是为特定分辨率(本示例中为 240x320)和具有默认四个硬件按钮的设备设计的。安装在具有其他规格的设备上将失败。
操作指南
处理非标准硬件按钮
本示例基于具有四个按钮的默认设备。如果您的目标设备有更多按钮,或者 MessageWindow
未捕获按钮交互,您将需要验证您的按钮代码。使用注册表编辑器(远程注册表编辑器)并转到 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shell\Keys\。您将看到多个“文件夹”,对应于您的硬件键,例如 40C1、40C2 等。将最后两个字母转换为十进制,您将获得按钮键(C1=193,C2=194,...)。
结论
此示例远非生产产品,但表明处理 PocketPC 等特定设备相当容易。与此类硬件交互需要一点 pinvoke,因为 compact framework 封装了部分但并非全部功能。欢迎任何评论/建议。
参考
历史
- 2007/10/08:发布到 CodeProject