无法在 Windows CE 上将字体更改为 "Arial"

Cannot change font to "Arial" on Windows CE

我们正在使用 Windows CE 6.0 设备并使用 .NET CF v2.0 进行编程。如果我在开机时立即启动我的应用程序(在 HKLM\init 中使用合适的注册表设置),则以下代码适用于 Label 控件但在 ListView 控件上失败:

cntrl.Font = new Font("Arial", cntrl.Font.Size, cntrl.Font.Style);

故障症状是即使在为 ListView 调用该代码后,Font.Name 仍然是 "Tahoma"。不知道为什么。

现在我编辑注册表以停止应用程序在开机时立即启动。重启设备,等待几秒钟,然后手动启动我的应用程序...现在代码适用于所有控件类型!

或者我添加一个快捷方式到 \Windows\Startup(或 HKLM\System\Explorer\Shell Folders\Startup 中指定的启动文件夹)。这会在延迟几秒后自动加载应用程序,这也有效。

在设计时,控件的字体为 "Tahoma",如果用户选择的语言是越南语,则将替换为 "Arial"。我附上了应用程序的两张图片以显示问题。

您会注意到 Label 控件不受影响,只有 ListView 控件受影响。我们有旧库存的 Windows CE 5.0 设备 运行 完全 相同的代码...并且它在这些设备上正常工作。这表明 Windows CE 6.0.

存在一些微妙的计时问题

最后,这只影响 "Arial" 和越南语。普通话(使用 "Droid Sans Fallback" 字体)和泰语(使用 "Loma" 字体)在所有设备上都能正常工作。

有什么想法吗?我可以做些什么来强制加载字体,或者等到字体加载完毕?

如果应用程序是使用 HKLM\Init 启动的,您必须确保所有需要的 APIs 和您的应用程序使用的资源都已准备就绪。有几种方法可以控制它:

  • 初始化入口序号

  • 取决于您应用的价值

  • WaitForAPI就绪函数

例如:

shell32.exe 进程是注册键 [HKLM]\Init\"Launch50"="shell32.exe" 并且依赖条目是 "Depend50"=hex(3): 14,00,1e,00。这意味着 OS 将在 Launch20 (0x14) 和 Launch30 (0x1e) 后面的进程发出信号开始时启动 shell32.exe。在示例中,Launch20 是 device.exe(驱动程序加载程序),Launch30 是 gwes.exe。这意味着 OS 将确保 shell32.exe 在这两个进程发出启动信号并且加载完成之前不会启动。

如果您使用 Depend51=0x14,00,0x1e,00 创建条目 Launch51,则在所需进程发出准备就绪信号之前,Launch51 的进程也不会启动。

此外,如果您正在使用 shell 或 GWES API 函数,则必须确保该函数已准备好使用。所以你需要调用 WaitForAPIReady 来检查,否则你的应用程序可能无法启动或 运行 正确。额外的字体加载可能取决于 GWES 和 GDI,因此您应该等待 SH_GDI。 GWES 加载已使用 Depend 条目进行检查。

即使您通过 Windows\StartUp 中的 lnk 文件启动进程,您也可能需要使用 WaitForApiReady。在启动过程的早期,某些资源可能仍然不可用。这种情况越早开始,例如通过 HKLM\init.

详细说明约瑟夫的回答:

* Use "WaitForAPIReady" (not "WinApiReady") on Windows CE 6.0 (or higher)

* Use "IsAPIReady" on CE 5.0 (or earlier)

* If using C# (which I was using) then you'll need to P/Invoke the functions:

    // If using Windows CE 6.0 (or higher)
    [DllImport("coredll.dll")]
    private static extern uint WaitForAPIReady(uint uAPISlotIndex, uint uTimeout);

    // If using Windows CE 5.0 (or earlier)
    [DllImport("coredll.dll")]
    private static extern bool IsAPIReady(uint hAPI);

* Define these constants:

    // If using Windows CE 6.0 (or higher)
    private const uint SH_GDI           = 80;
    private const uint SH_WMGR          = 81;
    private const uint SH_SHELL         = 85;

    // If using Windows CE 5.0 (or earlier)
    private const uint SH_GDI           = 16;
    private const uint SH_WMGR          = 17;
    private const uint SH_SHELL         = 21;

* If you need to be signalled that the OS is ready run this code:

    // If using Windows CE 6.0 (or higher)
    WaitForAPIReady(SH_GDI, 5000);
    WaitForAPIReady(SH_WMGR, 5000);
    WaitForAPIReady(SH_SHELL, 5000);

    // If using Windows CE 5.0 (or earlier) (IsAPIReady is a polling function)
    int nTimeout = 0;
    while ((!IsAPIReady(SH_GDI)) && (nTimeout++ < 50))
        System.Threading.Thread.Sleep(100);

    nTimeout = 0;
    while ((!IsAPIReady(SH_WMGR)) && (nTimeout++ < 50))
        System.Threading.Thread.Sleep(100);

    nTimeout = 0;
    while ((!IsAPIReady(SH_SHELL)) && (nTimeout++ < 50))
        System.Threading.Thread.Sleep(100);

* Finally, to be absolutely sure the OS is ready, I pause for 1s more

    System.Threading.Thread.Sleep(1000);