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