在开发全屏应用时,经常需要在屏幕上显示一些额外的信息,比如时间、系统资源使用情况等。但是,由于Windows和DirectX的限制,实现这样的覆盖层并不简单。本文将介绍如何开发一个自定义的全屏应用覆盖层工具,包括DirectDraw覆盖层的实现、插件管理、键盘快捷键处理以及如何创建自定义插件。
覆盖层工具可以在全屏应用的顶部显示一个透明的窗口,这个窗口可以显示各种插件提供的信息。通过改变各种设置,可以启用或禁用不同的插件,并改变它们的行为。开发者可以创建自己的插件来显示特定的内容。
覆盖层的实现涉及到DirectDraw技术。DirectDraw覆盖层在nVidia硬件上有一些限制,比如不支持Alpha通道。如果使用nVidia显卡,建议使用带有浅灰色背景的较小覆盖层,或者尝试使用FakeAlpha选项,这会将覆盖层下方的屏幕内容复制到覆盖层上。但请注意,这种方法速度较慢,需要较高的渲染速率才能正常工作。
为了实现快捷键功能,使用了Win32的SetWindowHookEx方法来挂钩WH_KEYBOARD_LL事件。这样,当用户按下快捷键时,覆盖层可以响应并执行相应的操作。
插件通过反射加载。代码会搜索所有继承自IPlugin接口的类,并为每个类创建一个实例。每个插件都可以包含数据属性,用于保存自定义值(如颜色、格式等)。这些值会被保存在.ini文件中,并在插件创建后加载。
覆盖层工具的主要功能是显示自定义的覆盖层。它负责插件的管理,每个插件都可以在覆盖层上渲染自己的部分,最终形成一个完全定制的覆盖层。
插件的加载是通过反射实现的。代码会遍历当前域中的所有程序集,查找所有继承自IPlugin接口的类,并为每个类创建一个实例。
foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (Type t in a.GetTypes())
{
if (t.IsAbstract || t.IsInterface || t.GetInterface(typeof(IPlugin).FullName) == null)
{
continue;
}
IPlugin p = (IPlugin)a.CreateInstance(t.FullName);
// ...
}
}
所有插件都有一个OnTick()和OnRender(Graphics g)方法。这些方法会由一个定时器调用,以便每个插件都有机会执行其任务。对于渲染,会应用一个TranslateTransform()矩阵操作,这样插件就可以从(0|0)开始渲染。
public static void OnRender(Graphics g)
{
g.Clear(General.BackgroundColor);
if (General.FakeAlpha)
{
g.CopyFromScreen(Overlay.Boundings.Location, Point.Empty, Overlay.Boundings.Size, CopyPixelOperation.SourceCopy);
}
foreach (IPlugin p in Plugins.Values)
{
if (p.Active && (p.Page == General.Page || p.Page == -1))
{
g.ResetTransform();
g.TranslateTransform(p.X, p.Y, MatrixOrder.Append);
p.Render(g);
}
}
}
目前程序中添加的插件包括:时间插件(显示时间)、CPU/内存插件(显示CPU使用率/可用内存)、颜色测试插件(显示不同颜色)、消息插件(监听UDP套接字并显示接收到的消息)、ATITool插件(读取ATI工具日志文件并显示GPU温度)等。
如果想创建自己的插件,只需将类添加到项目文件中,并在其中添加代码。这非常简单。没有添加动态编译/加载插件程序集的功能,因为认为没有必要,但可以自由地添加。
创建自定义插件的步骤如下: