From 7b2b37a87091eae835812d7eee3614faf26fbc85 Mon Sep 17 00:00:00 2001 From: Jonathan Jenne Date: Thu, 27 Jul 2023 15:47:02 +0200 Subject: [PATCH] Base: Add WindowsEx, ScreenEx --- Base/Base.vbproj | 3 +- Base/NativeMethods.vb | 237 ++++++++++++++++++++++++++++++++++++++++++ Base/PerformanceEx.vb | 44 -------- Base/ScreenEx.vb | 60 +++++++++++ Base/WindowsEx.vb | 36 +++++++ 5 files changed, 335 insertions(+), 45 deletions(-) create mode 100644 Base/NativeMethods.vb delete mode 100644 Base/PerformanceEx.vb create mode 100644 Base/WindowsEx.vb diff --git a/Base/Base.vbproj b/Base/Base.vbproj index 20832855..b1a98988 100644 --- a/Base/Base.vbproj +++ b/Base/Base.vbproj @@ -81,8 +81,10 @@ + + @@ -105,7 +107,6 @@ Settings.settings True - diff --git a/Base/NativeMethods.vb b/Base/NativeMethods.vb new file mode 100644 index 00000000..a63ec27e --- /dev/null +++ b/Base/NativeMethods.vb @@ -0,0 +1,237 @@ +Imports System.Runtime.InteropServices +Imports System.Text +Imports DigitalData.Modules.Base.ScreenEx + +Public Class NativeMethods + Public Declare Function GetWindowTextLength Lib "user32.dll" Alias "GetWindowTextLengthA" (ByVal hwnd As Int32) As Integer + Public Declare Function GetWindowText Lib "user32.dll" Alias "GetWindowTextA" (ByVal hWnd As IntPtr, ByVal WinTitle As String, ByVal MaxLength As Integer) As Integer + + Public Shared Function ShellExecuteEx(ByRef lpExecInfo As ShellExecuteInfo) As Boolean + End Function + + Public Shared Function SetClipboardViewer(ByVal hWnd As IntPtr) As IntPtr + End Function + + Public Shared Function GetDC(ByVal hwnd As IntPtr) As IntPtr + End Function + + Public Shared Function ReleaseDC(ByVal hwnd As IntPtr, ByVal hdc As IntPtr) As IntPtr + End Function + + Public Shared Function ReleaseCapture() As Boolean + End Function + + Public Shared Function GetWindowRect(ByVal hWnd As HandleRef, ByRef lpRect As RectangleAPI) As Boolean + End Function + + Public Shared Function AttachThreadInput(ByVal idAttach As IntPtr, ByVal idAttachTo As IntPtr, fAttach As Boolean) As Boolean + End Function + + Public Shared Function GetFocus() As IntPtr + End Function + + Public Shared Function WindowFromPoint(ByVal p As PointAPI) As IntPtr + End Function + + Public Shared Function GetForegroundWindow() As IntPtr + End Function + + Public Shared Function GetWindowThreadProcessId(ByVal hwnd As IntPtr, ByRef lpdwProcessID As Integer) As Integer + End Function + + Public Shared Function GetClassName(ByVal hwnd As Integer, ByVal lpClassName As StringBuilder, ByVal nMaxCount As Integer) As Integer + End Function + + Public Shared Function OpenProcess(ByVal dwDesiredAccess As UInteger, ByVal bInheritHandle As Boolean, ByVal dwProcessId As UInteger) As IntPtr + End Function + + Public Shared Function VirtualAllocEx(ByVal hProcess As IntPtr, ByVal lpAddress As IntPtr, ByVal dwSize As UIntPtr, ByVal flAllocationType As UInteger, ByVal flProtect As PageProtection) As IntPtr + End Function + + Public Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, ByRef lpdwProcessId As UInteger) As UInteger + End Function + + Public Shared Function VirtualFreeEx(ByVal hProcess As IntPtr, ByVal lpAddress As IntPtr, ByVal dwSize As UIntPtr, ByVal dwFreeType As UInteger) As Boolean + End Function + + Public Shared Function CloseHandle(ByVal hObject As IntPtr) As Boolean + End Function + + Public Shared Function MapViewOfFile(ByVal hFileMappingObject As IntPtr, ByVal dwDesiredAccess As UInteger, ByVal dwFileOffsetHigh As UInteger, ByVal dwFileOffsetLow As UInteger, ByVal dwNumberOfBytesToMap As UIntPtr) As IntPtr + End Function + + Public Shared Function UnmapViewOfFile(ByVal lpBaseAddress As IntPtr) As Boolean + End Function + + Public Shared Function CreateFileMapping(ByVal hFile As IntPtr, ByVal lpFileMappingAttributes As IntPtr, ByVal flProtect As PageProtection, ByVal dwMaximumSizeHigh As Integer, ByVal dwMaximumSizeLow As Integer, ByVal lpName As String) As IntPtr + End Function + + Public Shared Function SendMessage(ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr + End Function + + Public Shared Function ReadProcessMemory(ByVal hProcess As IntPtr, ByVal lpBaseAddress As IntPtr, + ByVal lpBuffer As Byte(), ByVal nSize As UIntPtr, ByVal lpNumberOfBytesRead As IntPtr) As Boolean + End Function + + Public Shared Sub MoveMemoryFromByte(ByVal dest As IntPtr, ByRef src As Byte, ByVal size As Integer) + End Sub + + Public Shared Sub MoveMemoryToByte(ByRef dest As Byte, ByVal src As IntPtr, ByVal size As Integer) + End Sub + + Public Shared Function RegisterWindowMessage(ByVal lpString As String) As Integer + End Function + + Public Shared Function GetCursorPos(ByRef lpPoint As PointAPI) As Boolean + End Function + + Friend Shared Function MonitorFromWindow(ByVal hwnd As IntPtr, + ByVal dwFlags As Integer) As IntPtr + End Function + + Friend Shared Function GetDpiForMonitor(ByVal hmonitor As IntPtr, + ByVal dpiType As Monitor_DPI_Type, + ByRef dpiX As UInteger, + ByRef dpiY As UInteger) As Integer + End Function + + Friend Shared Function GetDeviceCaps(ByVal hdc As IntPtr, ByVal nIndex As Integer) As Integer + End Function + + Public Declare Function RegisterHotKey Lib "user32" ( + ByVal Hwnd As IntPtr, + ByVal ID As Integer, + ByVal Modifiers As Integer, + ByVal Key As Integer + ) As Integer + + Public Declare Function UnregisterHotKey Lib "user32" ( + ByVal Hwnd As IntPtr, + ByVal ID As Integer + ) As Integer + + Public Declare Auto Function GetWindowText Lib "user32" ( + ByVal hWnd As IntPtr, + ByVal lpString As StringBuilder, + ByVal cch As Integer + ) As Integer + + Public Declare Function GlobalAddAtom Lib "kernel32" Alias "GlobalAddAtomA" (ByVal IDString As String) As Short + Public Declare Function GlobalDeleteAtom Lib "kernel32" (ByVal Atom As Short) As Short + + Public Const STANDARD_RIGHTS_REQUIRED As Integer = &HF0000 + + Public Const SECTION_QUERY As Short = &H1 + Public Const SECTION_MAP_WRITE As Short = &H2 + Public Const SECTION_MAP_READ As Short = &H4 + Public Const SECTION_MAP_EXECUTE As Short = &H8 + Public Const SECTION_EXTEND_SIZE As Short = &H10 + Public Const SECTION_ALL_ACCESS As Integer = STANDARD_RIGHTS_REQUIRED Or SECTION_QUERY Or SECTION_MAP_WRITE Or SECTION_MAP_READ Or SECTION_MAP_EXECUTE Or SECTION_EXTEND_SIZE + Public Const FILE_MAP_ALL_ACCESS As Integer = SECTION_ALL_ACCESS + + Public Const PROCESS_VM_OPERATION As Short = &H8 + Public Const PROCESS_VM_READ As Short = &H10 + Public Const PROCESS_VM_WRITE As Short = &H20 + Public Const PROCESS_ALL_ACCESS As Long = &H1F0FFF + + Public Const MEM_COMMIT As Short = &H1000 + Public Const MEM_RESERVE As Short = &H2000 + Public Const MEM_DECOMMIT As Short = &H4000 + Public Const MEM_RELEASE As Integer = &H8000 + Public Const MEM_FREE As Integer = &H10000 + Public Const MEM_PRIVATE As Integer = &H20000 + Public Const MEM_MAPPED As Integer = &H40000 + Public Const MEM_TOP_DOWN As Integer = &H100000 + + Public Const INVALID_HANDLE_VALUE As Integer = -1 + Public Const SW_SHOW As Short = 5 + + Public Const SEE_MASK_INVOKEIDLIST = &HC + Public Const SEE_MASK_NOCLOSEPROCESS = &H40 + Public Const SEE_MASK_FLAG_NO_UI = &H400 + + Public Const ULW_COLORKEY As Integer = &H1 + Public Const ULW_ALPHA As Integer = &H2 + Public Const ULW_OPAQUE As Integer = &H4 + + Public Const AC_SRC_OVER As Byte = &H0 + Public Const AC_SRC_ALPHA As Byte = &H1 + + Public Const HTCAPTION As Integer = &H2 + + Public Const WM_NCLBUTTONDOWN As Integer = &HA1 + Public Const WM_HOTKEY As Integer = &H312 + Public Const WM_DRAWCLIPBOARD As Integer = &H308 + + Public Enum PageProtection As UInteger + NoAccess = &H1 + [Readonly] = &H2 + ReadWrite = &H4 + WriteCopy = &H8 + Execute = &H10 + ExecuteRead = &H20 + ExecuteReadWrite = &H40 + ExecuteWriteCopy = &H80 + Guard = &H100 + NoCache = &H200 + WriteCombine = &H400 + End Enum + + Public Enum ChildWindowFromPointFlags As UInteger + CWP_ALL + CWP_SKIPINVISIBLE + CWP_SKIPDISABLED + CWP_SKIPTRANSPARENT + End Enum + + + Public Structure WINDOWPOS + Public hwnd As IntPtr + Public hwndInsertAfter As IntPtr + Public x As Integer + Public y As Integer + Public cx As Integer + Public cy As Integer + Public flags As Integer + End Structure + + Public Structure RectangleAPI + Public Left As Integer + Public Top As Integer + Public Right As Integer + Public Bottom As Integer + + Public Overrides Function ToString() As String + Return String.Format("Top: {0}, Bottom: {1}, Left: {2}, Right: {3}", Top, Bottom, Left, Right) + End Function + End Structure + + Public Structure ShellExecuteInfo + Public cbSize As Integer + Public fMask As Integer + Public hwnd As IntPtr + Public lpVerb As String + Public lpFile As String + Public lpParameters As String + Public lpDirectory As String + Dim nShow As Integer + Dim hInstApp As IntPtr + Dim lpIDList As IntPtr + Public lpClass As String + Public hkeyClass As IntPtr + Public dwHotKey As Integer + Public hIcon As IntPtr + Public hProcess As IntPtr + End Structure + + + Public Structure PointAPI + Public X As Integer + Public Y As Integer + + Public Sub New(ByVal X As Integer, ByVal Y As Integer) + Me.X = X + Me.Y = Y + End Sub + End Structure +End Class diff --git a/Base/PerformanceEx.vb b/Base/PerformanceEx.vb deleted file mode 100644 index 0ab72cba..00000000 --- a/Base/PerformanceEx.vb +++ /dev/null @@ -1,44 +0,0 @@ -Imports System.IO -Imports System.Reflection -Imports System.Runtime.InteropServices -Imports System.Security.Cryptography -Imports DigitalData.Modules.Logging - -Public Class PerformanceEx - Public Sub New(pLogConfig As LogConfig, pAppDataPath As String) - Dim savedHash = String.Empty - Dim assemblyLocation = Assembly.GetEntryAssembly().Location - - Dim hashPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "hash.txt") - If Not File.Exists(hashPath) Then - File.Create(hashPath) - Else - savedHash = File.ReadAllText(hashPath) - End If - - Dim hash = String.Concat(SHA1.Create().ComputeHash(File.ReadAllBytes(assemblyLocation)).Select(Function(x) x.ToString("x2"))) - If hash.Equals(savedHash) Then - Return - End If - - Dim dotNetRuntimePath = RuntimeEnvironment.GetRuntimeDirectory() - Dim ngenPath = Path.Combine(dotNetRuntimePath, "ngen.exe") - - Dim process = New Process With { - .StartInfo = New ProcessStartInfo With { - .FileName = ngenPath, - .Arguments = $"install ""{assemblyLocation}"" /nologo", - .CreateNoWindow = True, - .UseShellExecute = True, - .Verb = "runas" - } - } - Try - process.Start() - process.WaitForExit() - File.WriteAllText(hashPath, hash) - Catch - ' ... - End Try - End Sub -End Class diff --git a/Base/ScreenEx.vb b/Base/ScreenEx.vb index d70f15ca..199db45f 100644 --- a/Base/ScreenEx.vb +++ b/Base/ScreenEx.vb @@ -1,11 +1,30 @@ Imports System Imports System.Drawing +Imports System.Runtime.InteropServices Imports System.Windows.Forms +Imports DigitalData.Modules.Base.NativeMethods Public Class ScreenEx Public Const DEFAULT_WINDOW_HEIGHT = 480 Public Const DEFAULT_WINDOW_WIDTH = 640 + Friend Const MONITORINFOF_PRIMARY As Integer = &H1 + Friend Const MONITOR_DEFAULTTONEAREST As Integer = &H2 + Friend Const MONITOR_DEFAULTTONULL As Integer = &H0 + Friend Const MONITOR_DEFAULTTOPRIMARY As Integer = &H1 + + Friend Enum Monitor_DPI_Type As Integer + MDT_Effective_DPI = 0 + MDT_Angular_DPI = 1 + MDT_Raw_DPI = 2 + MDT_Default = MDT_Effective_DPI + End Enum + + Private Enum DeviceCap + VERTRES = 10 + DESKTOPVERTRES = 117 + End Enum + Public Shared Function GetLocationWithinScreen(pLocation As Point) As Point? For Each screen As Screen In Screen.AllScreens If screen.Bounds.Contains(pLocation) Then @@ -100,4 +119,45 @@ Public Class ScreenEx Return False End Function + + Public Function GetScreenScaling(Form As Form) As Single + Dim oHandle As IntPtr = Form.Handle + Dim oFactor1, oFactor2 As Single + + oFactor1 = GetFactorFromDeviceCaps(oHandle) + oFactor2 = GetDPIFromMonitor(oHandle) + + If oFactor1 > 1 Then + Return oFactor1 + Else + Return oFactor2 + End If + End Function + + Private Function GetFactorFromDeviceCaps(Handle As IntPtr) As Single + Dim g As Graphics = Graphics.FromHwnd(Handle) + Dim desktop As IntPtr = g.GetHdc() + Dim LogicalScreenHeight As Integer = GetDeviceCaps(desktop, DeviceCap.VERTRES) + Dim PhysicalScreenHeight As Integer = GetDeviceCaps(desktop, DeviceCap.DESKTOPVERTRES) + Dim oScreenScalingFactor As Single = CSng(PhysicalScreenHeight) / CSng(LogicalScreenHeight) + Return oScreenScalingFactor + End Function + + Private Function GetDPIFromMonitor(Handle As IntPtr) As Single + 'Get handle to monitor that contains this window. + Dim monitorHandle As IntPtr = MonitorFromWindow(Handle, MONITOR_DEFAULTTONEAREST) + + 'Get DPI (If the OS is not Windows 8.1 or newer, calling GetDpiForMonitor will cause exception). + Dim dpiX As UInteger + Dim dpiY As UInteger + + Dim result As Integer = GetDpiForMonitor(monitorHandle, Monitor_DPI_Type.MDT_Default, dpiX, dpiY) + + + If (result = 0) Then 'If S_OK (= 0) + Return dpiX / 96.0F + Else + Return -1 + End If + End Function End Class diff --git a/Base/WindowsEx.vb b/Base/WindowsEx.vb new file mode 100644 index 00000000..ecaa2374 --- /dev/null +++ b/Base/WindowsEx.vb @@ -0,0 +1,36 @@ +Imports System.ComponentModel +Imports System.Runtime.InteropServices +Imports DigitalData.Modules.Logging +Imports DigitalData.Modules.Base.NativeMethods + +Public Class WindowsEx + Private ReadOnly _LogConfig As LogConfig + Private ReadOnly _Logger As Logger + + Public Sub New(LogConfig As LogConfig) + _LogConfig = LogConfig + _Logger = LogConfig.GetLogger() + End Sub + + Public Function OpenFileProperties(FilePath As String) As Boolean + Try + Dim oShellExecuteInfo As New ShellExecuteInfo() + oShellExecuteInfo.cbSize = Marshal.SizeOf(oShellExecuteInfo) + oShellExecuteInfo.lpVerb = "properties" + oShellExecuteInfo.lpFile = FilePath + oShellExecuteInfo.nShow = SW_SHOW + oShellExecuteInfo.fMask = SEE_MASK_INVOKEIDLIST + + If Not ShellExecuteEx(oShellExecuteInfo) Then + Dim oWin32Error = Marshal.GetLastWin32Error() + Dim oException As New Win32Exception(oWin32Error) + Throw oException + End If + + Return True + Catch ex As Exception + _Logger.Error(ex) + Return False + End Try + End Function +End Class