我正在写一个(非常)小的应用程序,它只是在开始时执行一些小的操作,应该在屏幕上写一条消息,类似于屏幕显示:大字母,没有任何窗口,高于一切,可见某个时刻然后逐渐消失。
如果可能,我不想为它创建一个窗口。
这样做的正确方法是什么?
(我希望没有像DirectX这样的特殊工具包,需要直接图形访问等)
答案 0 :(得分:8)
正如评论中指出的那样,您可以直接绘制到屏幕上。 GetDC提供返回适当的设备上下文:
hWnd [in]
要检索其DC的窗口的句柄。 如果此值为NULL,则GetDC将检索整个屏幕的DC。
直接渲染到屏幕会产生至少两个需要解决的问题:
这两个问题都可以通过创建窗口来解决。窗口不需要具有边框,标题栏,系统菜单或最小化/最大化/关闭按钮。相应的Window Styles为WS_POPUP | WS_VISIBLE
。
要使窗口显示在其他所有内容之前,需要将其标记为最顶层(使用WS_EX_TOPMOST
Extended Window Style)。请注意,这会将窗口置于Z顺序中所有其他非最顶层窗口的上方。你仍然需要与其他最顶级的窗户战斗(你无法赢得的军备竞赛)。
要实现透明度,窗口必须具有WS_EX_LAYERED
扩展窗口样式以创建Layered Window。然后调用SetLayeredWindowAttributes启用Alpha透明度。为了使窗口背景完全透明,无论窗口的alpha透明度如何,您还需要启用颜色键控。一种简单的方法是将WNDCLASSEX structure的hbrBackground
成员设置为(HBRUSH)GetStockObject(BLACK_BRUSH)
,并在调用{RGB(0, 0, 0)
中指定crKey
参数{1}}。
SetLayeredWindowAttributes
首先注册主应用程序窗口类。重要的是#define STRICT 1
#define WIN32_LEAN_AND_MEAN
#include <SDKDDKVer.h>
#include <windows.h>
// Forward declarations
LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );
// Entry point
int APIENTRY wWinMain( HINSTANCE hInstance,
HINSTANCE /*hPrevInstance*/,
LPTSTR /*lpCmdLine*/,
int nCmdShow ) {
成员。这可以控制背景渲染,并最终使其完全透明。
hbrBackground
这是实例化窗口并调整其属性所需的所有设置代码。启用Alpha透明度以准备淡出效果,而颜色键控遮盖了窗口中未渲染的区域。
const wchar_t k_WndClassName[] = L"OverlayWindowClass";
// Register window class
WNDCLASSEXW wcex = { 0 };
wcex.cbSize = sizeof( wcex );
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.hCursor = ::LoadCursorW( NULL, IDC_ARROW );
wcex.hbrBackground = (HBRUSH)::GetStockObject( BLACK_BRUSH );
wcex.lpszClassName = k_WndClassName;
::RegisterClassExW( &wcex );
HWND hWnd = ::CreateWindowExW( WS_EX_TOPMOST | WS_EX_LAYERED,
k_WndClassName,
L"Overlay Window",
WS_POPUP | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
800, 600,
NULL, NULL,
hInstance,
NULL );
// Make window semi-transparent, and mask out background color
::SetLayeredWindowAttributes( hWnd, RGB( 0, 0, 0 ), 128, LWA_ALPHA | LWA_COLORKEY );
的剩余部分是样板窗口应用程序代码。
wWinMain
窗口过程执行简单渲染。为了演示alpha和键颜色透明度,代码呈现一个白色椭圆,客户区域为边界矩形。此外,还处理WM_NCHITTEST message,以提供使用鼠标或其他指针设备在屏幕上拖动窗口的简单方法。请注意,鼠标输入将传递到下面的窗口,用于完全透明的所有区域。
::ShowWindow( hWnd, nCmdShow );
::UpdateWindow( hWnd );
// Main message loop:
MSG msg = { 0 };
while ( ::GetMessageW( &msg, NULL, 0, 0 ) > 0 )
{
::TranslateMessage( &msg );
::DispatchMessageW( &msg );
}
return (int)msg.wParam;
}
<小时/> 备用
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch ( message )
{
case WM_PAINT:
{
PAINTSTRUCT ps = { 0 };
HDC hDC = ::BeginPaint( hWnd, &ps );
RECT rc = { 0 };
::GetClientRect( hWnd, &rc );
HBRUSH hbrOld = (HBRUSH)::SelectObject( hDC,
::GetStockObject( WHITE_BRUSH ) );
::Ellipse( hDC, rc.left, rc.top, rc.right, rc.bottom );
::SelectObject( hDC, hbrOld );
::EndPaint( hWnd, &ps );
}
return 0;
case WM_NCHITTEST:
return HTCAPTION;
case WM_DESTROY:
::PostQuitMessage( 0 );
return 0;
default:
break;
}
return ::DefWindowProc( hWnd, message, wParam, lParam );
}
处理程序,用于输出文本。使用与键颜色不同的文本颜色非常重要。如果要使用黑色文本,则必须使用不同的键颜色。
WM_PAINT
答案 1 :(得分:0)
我还希望能够直接写入屏幕(在示例中是显示实际的 Windows 版本信息)。我做了很多搜索,终于能够拼凑出代码......
Imports System.Environment
Public Class frmMain
Dim stringFont As Font
Dim string_format As New StringFormat()
Dim my_WinName As String
Const my_WinStatic As String = " ver. "
Dim my_WinVersion As String
Dim my_WinRelease As String
Dim my_WinBuild As String
Dim my_WinSubBuild As String
Dim my_Delim1 As String
Dim emb_Delim1 As Boolean
Dim my_Delim2 As String
Dim emb_Delim2 As Boolean
Dim txt_Display_Ver As String
Dim txt_Curr_Build As String
Dim txt_UBR_Value As String
Dim the_File As String
Dim version_Complete As Boolean
Dim current_Ver As String
Dim previous_Ver As String
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Try
If My.Settings.UpgradeRequired = True Then
My.Settings.Upgrade()
My.Settings.UpgradeRequired = False
My.Settings.Save()
End If
Catch ex As Exception
MessageBox.Show(ex.Message, "Upgrade from Previous Version Error")
End Try
conMenuAbout.Text = My.Application.Info.AssemblyName & " (ver. " & My.Application.Info.Version.ToString & ")"
prop_Grid.SelectedObject = My.Settings
string_format.Alignment = StringAlignment.Far
string_format.LineAlignment = StringAlignment.Near
version_Complete = False
form_Defaults()
Me.WindowState = FormWindowState.Minimized
nextTime.Interval = 500
nextTime.Start()
End Sub
Private Sub nextTime_Tick(sender As Object, e As EventArgs) Handles nextTime.Tick
Dim d As Graphics = Graphics.FromHwnd(IntPtr.Zero)
Dim brush_Name As System.Drawing.Brush = New System.Drawing.SolidBrush(My.Settings.color_Win_Name)
Dim brush_Static As System.Drawing.Brush = New System.Drawing.SolidBrush(My.Settings.color_static_Ver)
Dim brush_WinVer As System.Drawing.Brush = New System.Drawing.SolidBrush(My.Settings.color_Win_Version)
Dim brush_CharDelim As System.Drawing.Brush = New System.Drawing.SolidBrush(My.Settings.color_Char_Delim)
Dim brush_Curr_Rel As System.Drawing.Brush = New System.Drawing.SolidBrush(My.Settings.color_Curr_Release)
Dim brush_Curr_Bld As System.Drawing.Brush = New System.Drawing.SolidBrush(My.Settings.color_Curr_Build)
Dim brush_UBR_Delim As System.Drawing.Brush = New System.Drawing.SolidBrush(My.Settings.color_UBR_Delim)
Dim brush_UBR_Rev As System.Drawing.Brush = New System.Drawing.SolidBrush(My.Settings.color_UpdateBldRev)
update_Version()
Dim writeHere As New PointF(Screen.PrimaryScreen.Bounds.Right - 300, Screen.PrimaryScreen.Bounds.Bottom - 64)
d.DrawString(my_WinName, stringFont, brush_Name, writeHere)
writeHere.X += d.MeasureString(my_WinName, stringFont).Width - My.Settings.Space_1
d.DrawString(my_WinStatic, stringFont, brush_Static, writeHere)
writeHere.X += d.MeasureString(my_WinStatic, stringFont).Width - My.Settings.Space_2
d.DrawString(my_WinVersion, stringFont, brush_WinVer, writeHere)
writeHere.X += d.MeasureString(my_WinVersion, stringFont).Width - My.Settings.Space_3
d.DrawString(my_Delim1, stringFont, brush_CharDelim, writeHere)
writeHere.X += d.MeasureString(my_Delim1, stringFont).Width - My.Settings.Space_4
d.DrawString(my_WinRelease, stringFont, brush_Curr_Rel, writeHere)
writeHere.X += d.MeasureString(my_WinRelease, stringFont).Width - My.Settings.Space_5
d.DrawString(my_Delim1, stringFont, brush_CharDelim, writeHere)
writeHere.X += d.MeasureString(my_Delim1, stringFont).Width - My.Settings.Space_6
d.DrawString(my_WinBuild, stringFont, brush_Curr_Bld, writeHere)
writeHere.X += d.MeasureString(my_WinBuild, stringFont).Width - My.Settings.Space_7
d.DrawString(my_Delim2, stringFont, brush_UBR_Delim, writeHere)
writeHere.X += d.MeasureString(my_Delim2, stringFont).Width - My.Settings.Space_8
d.DrawString(my_WinSubBuild, stringFont, brush_UBR_Rev, writeHere)
End Sub
Public Sub form_Defaults()
Try
nextTime.Interval = My.Settings.updateInterval
Me.Opacity = My.Settings.Opacity / 100
my_Delim1 = My.Settings.char_Delimiter
emb_Delim1 = My.Settings.embolden_Char_Delim
my_Delim2 = My.Settings.UBR_Delimiter
emb_Delim2 = My.Settings.embolden_UBR_Char
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
update_Version()
If current_Ver <> previous_Ver Then
Try
If Not String.IsNullOrEmpty(My.Settings.text_Version_File) Then
the_File = My.Settings.text_Version_File
Else
ofd.FileName = "WinVer.txt"
If ofd.ShowDialog = DialogResult.OK Then
My.Settings.text_Version_File = ofd.FileName
the_File = ofd.FileName
End If
End If
Catch ex As Exception
Dim str_Err = ex.Message
ofd.FileName = "WinVer.txt"
If ofd.ShowDialog = DialogResult.OK Then
My.Settings.text_Version_File = ofd.FileName
the_File = ofd.FileName
End If
End Try
conMenuSaveVer_Click(Nothing, Nothing)
previous_Ver = current_Ver
End If
End Sub
Private Sub update_Version()
Try
Dim tmpStr As String = My.Computer.Registry.GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductName", Nothing)
my_WinName = Replace(tmpStr, "Windows ", "Win ")
tmpStr = Replace(my_WinName, "Professional", "Pro")
my_WinName = Replace(tmpStr, "Enterprise", "Pro")
my_WinVersion = My.Computer.Registry.GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentVersion", Nothing)
my_WinRelease = My.Computer.Registry.GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "DisplayVersion", Nothing)
my_WinBuild = My.Computer.Registry.GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentBuild", Nothing)
Dim myKey As Microsoft.Win32.RegistryKey = Microsoft.Win32.RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, Microsoft.Win32.RegistryView.Registry64)
Dim myKey2 As Object = myKey.OpenSubKey("SOFTWARE\Microsoft\Windows NT\CurrentVersion")
Dim myVal As Int64 = Convert.ToInt64(myKey2.GetValue("UBR").ToString)
my_WinSubBuild = myVal
current_Ver = my_WinName & my_WinVersion & my_WinRelease & my_WinBuild & my_WinSubBuild
stringFont = New Font(My.Settings.useFont, My.Settings.useFont.Style)
version_Complete = True
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Private Sub conMenuExit_Click(sender As Object, e As EventArgs) Handles conMenuExit.Click
Application.Exit()
End Sub
Private Sub conMenuSettings_Click(sender As Object, e As EventArgs) Handles conMenuSettings.Click
Me.WindowState = FormWindowState.Normal
End Sub
Private Sub frmMain_Resize(sender As Object, e As EventArgs) Handles MyBase.Resize
If Me.WindowState = FormWindowState.Minimized Then
Me.sysTrayIcon.Visible = True
Me.ShowInTaskbar = False
Else
Me.ShowInTaskbar = True
Me.sysTrayIcon.Visible = False
End If
End Sub
Private Sub frmMain_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
e.Cancel = True
Me.WindowState = FormWindowState.Minimized
End Sub
Private Sub conMenuSaveVer_Click(sender As Object, e As EventArgs) Handles conMenuSaveVer.Click
If version_Complete = False Then
Exit Sub
End If
Try
My.Computer.FileSystem.WriteAllText(the_File, current_Ver, False)
Catch ex As Exception
MessageBox.Show(Me, ex.Message, "Save Version Error")
End Try
Try
If Not String.IsNullOrEmpty(current_Ver) Then
If Not String.IsNullOrWhiteSpace(current_Ver) Then
Clipboard.SetText(current_Ver)
End If
End If
Catch ex As Exception
MessageBox.Show(Me, ex.Message, "Clipboard Error")
End Try
End Sub
End Class