From 0f112133826985b2a7f02751bd5ef753235e7d2b Mon Sep 17 00:00:00 2001 From: Kaneko Qt Date: Thu, 4 Apr 2024 03:20:11 +0300 Subject: [PATCH] Port to .NET Framework 4.6 --- .vscode/launch.json | 19 +++--------- .vscode/tasks.json | 33 ++++---------------- MediaOsd.cs | 59 ------------------------------------ NativeMethods.txt | 11 ------- ReMOSD.csproj | 27 +++++------------ src/MediaOsd.cs | 55 +++++++++++++++++++++++++++++++++ src/PInvoke.cs | 40 ++++++++++++++++++++++++ Program.cs => src/Program.cs | 27 ++++++++--------- 8 files changed, 125 insertions(+), 146 deletions(-) delete mode 100644 MediaOsd.cs delete mode 100644 NativeMethods.txt create mode 100644 src/MediaOsd.cs create mode 100644 src/PInvoke.cs rename Program.cs => src/Program.cs (71%) diff --git a/.vscode/launch.json b/.vscode/launch.json index 8594e1f..d3b0e4a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,24 +1,13 @@ { - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { - "name": ".NET Core Launch (console)", + "name": "Launch", "type": "coreclr", "request": "launch", - "preLaunchTask": "build", - "program": "${workspaceFolder}/bin/Debug/net7.0/ReMOSD.dll", - "args": [], - "cwd": "${workspaceFolder}", - "console": "externalTerminal", - "stopAtEntry": false - }, - { - "name": ".NET Core Attach", - "type": "coreclr", - "request": "attach" + "preLaunchTask": "Build", + "program": "${workspaceFolder}/bin/ReMOSD.dll", + "console": "integratedTerminal" } ] } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 777d2a9..16dcd4b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,39 +2,18 @@ "version": "2.0.0", "tasks": [ { - "label": "build", + "label": "Build", "command": "dotnet", "type": "process", - "args": [ - "build", - "${workspaceFolder}/ReMOSD.csproj", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" - ], - "problemMatcher": "$msCompile" - }, - { - "label": "publish", - "command": "dotnet", - "type": "process", - "args": [ - "publish", - "${workspaceFolder}/ReMOSD.csproj", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" - ], - "problemMatcher": "$msCompile" + "args": ["build"], + "problemMatcher": "$msCompile", + "isBuildCommand": true }, { - "label": "watch", + "label": "Publish", "command": "dotnet", "type": "process", - "args": [ - "watch", - "run", - "--project", - "${workspaceFolder}/ReMOSD.csproj" - ], + "args": ["publish", "-f", "net46"], "problemMatcher": "$msCompile" } ] diff --git a/MediaOsd.cs b/MediaOsd.cs deleted file mode 100644 index b02022e..0000000 --- a/MediaOsd.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.ComponentModel; -using System.Runtime.InteropServices; -using System.Threading; - -using Windows.Win32.Foundation; -using Windows.Win32.Graphics.Gdi; - -using static Windows.Win32.System.SystemServices.APPCOMMAND_ID; -using static Windows.Win32.PInvoke; - -class MediaOsd -{ - const string _className = "NativeHWNDHost\0"; - - public HWND HWnd { get; private set; } - - public HRGN Region - { - set { - var result = SetWindowRgn(HWnd, value, true); - if (result == 0) throw new Win32Exception(Marshal.GetLastWin32Error()); - } - } - - public uint Dpi - { - get { - var dpi = GetDpiForWindow(HWnd); - if (dpi == 0) throw new Win32Exception(Marshal.GetLastWin32Error()); - - return dpi; - } - } - - MediaOsd() {} - - public static MediaOsd Find() - { - var osd = new MediaOsd(); - - // Trigger show volume control window so it is created and can be found later - // (to pack APPCOMMAND lParam https://stackoverflow.com/a/29301152/18449435) - // (https://forums.codeguru.com/showthread.php?147192-How-to-construct-WM_APPCOMMAND-message) - SendMessage(GetShellWindow(), WM_APPCOMMAND, 0, (int)APPCOMMAND_VOLUME_MUTE << 16); - SendMessage(GetShellWindow(), WM_APPCOMMAND, 0, (int)APPCOMMAND_VOLUME_MUTE << 16); - - for (var attempt = 1; attempt <= 5; ++attempt) - { - osd.HWnd = FindWindowEx(default, default, _className, default); - if (osd.HWnd != default) break; - - Thread.Sleep(250); - } - if (osd.HWnd == default) throw new Exception("Media OSD was not found :("); - - return osd; - } -} \ No newline at end of file diff --git a/NativeMethods.txt b/NativeMethods.txt deleted file mode 100644 index 0eade9c..0000000 --- a/NativeMethods.txt +++ /dev/null @@ -1,11 +0,0 @@ -GetShellWindow -WM_APPCOMMAND -APPCOMMAND_ID -SendMessage -FindWindowEx - -AllocConsole - -GetDpiForWindow -CreateRectRgn -SetWindowRgn \ No newline at end of file diff --git a/ReMOSD.csproj b/ReMOSD.csproj index 8adc01e..785edef 100644 --- a/ReMOSD.csproj +++ b/ReMOSD.csproj @@ -2,32 +2,21 @@ WinExe - net8.0 + net8.0 + latest enable - win-x64 - - - - CA1416 - + net46 + false + true - + true + false + none bin bin false false - - true - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - \ No newline at end of file diff --git a/src/MediaOsd.cs b/src/MediaOsd.cs new file mode 100644 index 0000000..088686c --- /dev/null +++ b/src/MediaOsd.cs @@ -0,0 +1,55 @@ +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Threading; + +using static ReMOSD.PInvoke; + +namespace ReMOSD; + +class MediaOsd +{ + public nint HWnd { get; private set; } + + MediaOsd() {} + + public void SetRegion(nint value) + { + var result = SetWindowRgn(HWnd, value, true); + if (result == 0) throw new Win32Exception(Marshal.GetLastWin32Error()); + } + + public uint GetDpi() + { + var dpi = GetDpiForWindow(HWnd); + if (dpi == 0) throw new Win32Exception(Marshal.GetLastWin32Error()); + + return dpi; + } + + public static MediaOsd Find() + { + var shellHWnd = GetShellWindow(); + + // Trigger show volume control window so it is created and can be found later + // (to pack APPCOMMAND lParam https://stackoverflow.com/a/29301152/18449435) + // (https://forums.codeguru.com/showthread.php?147192-How-to-construct-WM_APPCOMMAND-message) + SendMessage(shellHWnd, WM_APPCOMMAND, 0, (int)APPCOMMAND_VOLUME_MUTE << 16); + SendMessage(shellHWnd, WM_APPCOMMAND, 0, (int)APPCOMMAND_VOLUME_MUTE << 16); + + var hWnd = default(nint); + for (var attempt = 1; attempt <= 5; ++attempt) + { + hWnd = FindWindowExA(default, default, "NativeHWNDHost\0", default); + if (hWnd != default) break; + + Thread.Sleep(250); + } + if (hWnd == default) throw new InvalidOperationException("Media OSD was not found :("); + + var osd = new MediaOsd() { + HWnd = hWnd + }; + return osd; + } +} \ No newline at end of file diff --git a/src/PInvoke.cs b/src/PInvoke.cs new file mode 100644 index 0000000..c039b4f --- /dev/null +++ b/src/PInvoke.cs @@ -0,0 +1,40 @@ +using System.Runtime.InteropServices; + +namespace ReMOSD; + +static partial class PInvoke +{ + /// https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-appcommand + public const uint WM_APPCOMMAND = 793; + + /// https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-appcommand + public const uint APPCOMMAND_VOLUME_MUTE = 8; + + /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowrgn + [DllImport("user32.dll")] + public static extern int SetWindowRgn(nint hWnd, nint hRgn, bool bRedraw); + + /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpiforwindow + [DllImport("user32.dll")] + public static extern uint GetDpiForWindow(nint hWnd); + + /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getshellwindow + [DllImport("user32.dll")] + public static extern nint GetShellWindow(); + + /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendmessage + [DllImport("user32.dll")] + public static extern nint SendMessage(nint hWnd, uint Msg, nint wParam, nint lParam); + + /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-findwindowexa + [DllImport("user32.dll")] + public static extern nint FindWindowExA(nint hWndParent, nint hWndChildAfter, string lpszClass, string? lpszWindow); + + /// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createrectrgn + [DllImport("gdi32.dll")] + public static extern nint CreateRectRgn(int x1, int y1, int x2, int y2); + + /// https://learn.microsoft.com/en-us/windows/console/allocconsole + [DllImport("kernel32.dll")] + public static extern bool AllocConsole(); +} \ No newline at end of file diff --git a/Program.cs b/src/Program.cs similarity index 71% rename from Program.cs rename to src/Program.cs index 309e4a7..ed229e3 100644 --- a/Program.cs +++ b/src/Program.cs @@ -1,34 +1,31 @@ -using System; +using System; using System.ComponentModel; -using System.Drawing; using System.Linq; using System.Runtime.InteropServices; -using Windows.Win32.Graphics.Gdi; - -using static Windows.Win32.PInvoke; - - -Size _miniOsdSize = new(65, 140); +using ReMOSD; +using static ReMOSD.PInvoke; AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; var osd = MediaOsd.Find(); -HRGN newOsdRegion; -if (args.Contains("--restore") || args.Contains("-r")) newOsdRegion = new HRGN(); +IntPtr newOsdRegion; +if (args.Contains("--restore") || args.Contains("-r")) +{ + newOsdRegion = new IntPtr(); +} else { - var osdScalingCoefficient = osd.Dpi / 96.0f; + var osdScalingCoefficient = osd.GetDpi() / 96.0f; newOsdRegion = CreateRectRgn(0, 0, - (int)Math.Round(_miniOsdSize.Width * osdScalingCoefficient), - (int)Math.Round(_miniOsdSize.Height * osdScalingCoefficient)); + (int)Math.Round(65 * osdScalingCoefficient), + (int)Math.Round(140 * osdScalingCoefficient)); if (newOsdRegion == default) throw new Win32Exception(Marshal.GetLastWin32Error()); } -osd.Region = newOsdRegion; - +osd.SetRegion(newOsdRegion); static void OnUnhandledException(object s, UnhandledExceptionEventArgs e) {