├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── WindowSharingHider.sln ├── WindowSharingHider ├── App.config ├── MainWindow.Designer.cs ├── MainWindow.cs ├── MainWindow.resx ├── Program.cs ├── WindowHandler.cs └── WindowSharingHider.csproj └── cert.pfx.enc /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015/2017 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # Visual Studio 2017 auto generated files 34 | Generated\ Files/ 35 | 36 | # MSTest test Results 37 | [Tt]est[Rr]esult*/ 38 | [Bb]uild[Ll]og.* 39 | 40 | # NUNIT 41 | *.VisualState.xml 42 | TestResult.xml 43 | 44 | # Build Results of an ATL Project 45 | [Dd]ebugPS/ 46 | [Rr]eleasePS/ 47 | dlldata.c 48 | 49 | # Benchmark Results 50 | BenchmarkDotNet.Artifacts/ 51 | 52 | # .NET Core 53 | project.lock.json 54 | project.fragment.lock.json 55 | artifacts/ 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_h.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *_wpftmp.csproj 81 | *.log 82 | *.vspscc 83 | *.vssscc 84 | .builds 85 | *.pidb 86 | *.svclog 87 | *.scc 88 | 89 | # Chutzpah Test files 90 | _Chutzpah* 91 | 92 | # Visual C++ cache files 93 | ipch/ 94 | *.aps 95 | *.ncb 96 | *.opendb 97 | *.opensdf 98 | *.sdf 99 | *.cachefile 100 | *.VC.db 101 | *.VC.VC.opendb 102 | 103 | # Visual Studio profiler 104 | *.psess 105 | *.vsp 106 | *.vspx 107 | *.sap 108 | 109 | # Visual Studio Trace Files 110 | *.e2e 111 | 112 | # TFS 2012 Local Workspace 113 | $tf/ 114 | 115 | # Guidance Automation Toolkit 116 | *.gpState 117 | 118 | # ReSharper is a .NET coding add-in 119 | _ReSharper*/ 120 | *.[Rr]e[Ss]harper 121 | *.DotSettings.user 122 | 123 | # JustCode is a .NET coding add-in 124 | .JustCode 125 | 126 | # TeamCity is a build add-in 127 | _TeamCity* 128 | 129 | # DotCover is a Code Coverage Tool 130 | *.dotCover 131 | 132 | # AxoCover is a Code Coverage Tool 133 | .axoCover/* 134 | !.axoCover/settings.json 135 | 136 | # Visual Studio code coverage results 137 | *.coverage 138 | *.coveragexml 139 | 140 | # NCrunch 141 | _NCrunch_* 142 | .*crunch*.local.xml 143 | nCrunchTemp_* 144 | 145 | # MightyMoose 146 | *.mm.* 147 | AutoTest.Net/ 148 | 149 | # Web workbench (sass) 150 | .sass-cache/ 151 | 152 | # Installshield output folder 153 | [Ee]xpress/ 154 | 155 | # DocProject is a documentation generator add-in 156 | DocProject/buildhelp/ 157 | DocProject/Help/*.HxT 158 | DocProject/Help/*.HxC 159 | DocProject/Help/*.hhc 160 | DocProject/Help/*.hhk 161 | DocProject/Help/*.hhp 162 | DocProject/Help/Html2 163 | DocProject/Help/html 164 | 165 | # Click-Once directory 166 | publish/ 167 | 168 | # Publish Web Output 169 | *.[Pp]ublish.xml 170 | *.azurePubxml 171 | # Note: Comment the next line if you want to checkin your web deploy settings, 172 | # but database connection strings (with potential passwords) will be unencrypted 173 | *.pubxml 174 | *.publishproj 175 | 176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 177 | # checkin your Azure Web App publish settings, but sensitive information contained 178 | # in these scripts will be unencrypted 179 | PublishScripts/ 180 | 181 | # NuGet Packages 182 | *.nupkg 183 | # The packages folder can be ignored because of Package Restore 184 | **/[Pp]ackages/* 185 | # except build/, which is used as an MSBuild target. 186 | !**/[Pp]ackages/build/ 187 | # Uncomment if necessary however generally it will be regenerated when needed 188 | #!**/[Pp]ackages/repositories.config 189 | # NuGet v3's project.json files produces more ignorable files 190 | *.nuget.props 191 | *.nuget.targets 192 | 193 | # Microsoft Azure Build Output 194 | csx/ 195 | *.build.csdef 196 | 197 | # Microsoft Azure Emulator 198 | ecf/ 199 | rcf/ 200 | 201 | # Windows Store app package directories and files 202 | AppPackages/ 203 | BundleArtifacts/ 204 | Package.StoreAssociation.xml 205 | _pkginfo.txt 206 | *.appx 207 | 208 | # Visual Studio cache files 209 | # files ending in .cache can be ignored 210 | *.[Cc]ache 211 | # but keep track of directories ending in .cache 212 | !*.[Cc]ache/ 213 | 214 | # Others 215 | ClientBin/ 216 | ~$* 217 | *~ 218 | *.dbmdl 219 | *.dbproj.schemaview 220 | *.jfm 221 | *.pfx 222 | *.publishsettings 223 | orleans.codegen.cs 224 | 225 | # Including strong name files can present a security risk 226 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 227 | #*.snk 228 | 229 | # Since there are multiple workflows, uncomment next line to ignore bower_components 230 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 231 | #bower_components/ 232 | 233 | # RIA/Silverlight projects 234 | Generated_Code/ 235 | 236 | # Backup & report files from converting an old project file 237 | # to a newer Visual Studio version. Backup files are not needed, 238 | # because we have git ;-) 239 | _UpgradeReport_Files/ 240 | Backup*/ 241 | UpgradeLog*.XML 242 | UpgradeLog*.htm 243 | ServiceFabricBackup/ 244 | *.rptproj.bak 245 | 246 | # SQL Server files 247 | *.mdf 248 | *.ldf 249 | *.ndf 250 | 251 | # Business Intelligence projects 252 | *.rdl.data 253 | *.bim.layout 254 | *.bim_*.settings 255 | *.rptproj.rsuser 256 | 257 | # Microsoft Fakes 258 | FakesAssemblies/ 259 | 260 | # GhostDoc plugin setting file 261 | *.GhostDoc.xml 262 | 263 | # Node.js Tools for Visual Studio 264 | .ntvs_analysis.dat 265 | node_modules/ 266 | 267 | # Visual Studio 6 build log 268 | *.plg 269 | 270 | # Visual Studio 6 workspace options file 271 | *.opt 272 | 273 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 274 | *.vbw 275 | 276 | # Visual Studio LightSwitch build output 277 | **/*.HTMLClient/GeneratedArtifacts 278 | **/*.DesktopClient/GeneratedArtifacts 279 | **/*.DesktopClient/ModelManifest.xml 280 | **/*.Server/GeneratedArtifacts 281 | **/*.Server/ModelManifest.xml 282 | _Pvt_Extensions 283 | 284 | # Paket dependency manager 285 | .paket/paket.exe 286 | paket-files/ 287 | 288 | # FAKE - F# Make 289 | .fake/ 290 | 291 | # JetBrains Rider 292 | .idea/ 293 | *.sln.iml 294 | 295 | # CodeRush personal settings 296 | .cr/personal 297 | 298 | # Python Tools for Visual Studio (PTVS) 299 | __pycache__/ 300 | *.pyc 301 | 302 | # Cake - Uncomment if you are using it 303 | # tools/** 304 | # !tools/packages.config 305 | 306 | # Tabs Studio 307 | *.tss 308 | 309 | # Telerik's JustMock configuration file 310 | *.jmconfig 311 | 312 | # BizTalk build output 313 | *.btp.cs 314 | *.btm.cs 315 | *.odx.cs 316 | *.xsd.cs 317 | 318 | # OpenCover UI analysis results 319 | OpenCover/ 320 | 321 | # Azure Stream Analytics local run output 322 | ASALocalRun/ 323 | 324 | # MSBuild Binary and Structured Log 325 | *.binlog 326 | 327 | # NVidia Nsight GPU debugger configuration file 328 | *.nvuser 329 | 330 | # MFractors (Xamarin productivity tool) working folder 331 | .mfractor/ 332 | 333 | # Local History for Visual Studio 334 | .localhistory/ 335 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 shalzuth 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Window Sharing Hider 2 | Hides Windows during screen sharing. Works with Teams, Zoom, Discord, etc. 3 | 4 | Single app, no dll's, works on both x86/x64 5 | 6 | Relies on [SetWindowDisplayAffinity](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowdisplayaffinity). Microsoft specifically restricted it to only work on windows where the current process is the owner of the window. This works by creating a thread in the target process to bypass that restriction. -------------------------------------------------------------------------------- /WindowSharingHider.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31112.23 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowSharingHider", "WindowSharingHider\WindowSharingHider.csproj", "{9A4DE5B4-64FC-4B26-B1F6-A07904AC33F1}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {9A4DE5B4-64FC-4B26-B1F6-A07904AC33F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {9A4DE5B4-64FC-4B26-B1F6-A07904AC33F1}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {9A4DE5B4-64FC-4B26-B1F6-A07904AC33F1}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {9A4DE5B4-64FC-4B26-B1F6-A07904AC33F1}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {676CEE7C-D20E-4F11-88F5-1220E0A761B0} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /WindowSharingHider/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /WindowSharingHider/MainWindow.Designer.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace WindowSharingHider 3 | { 4 | partial class MainWindow 5 | { 6 | /// 7 | /// Required designer variable. 8 | /// 9 | private System.ComponentModel.IContainer components = null; 10 | 11 | /// 12 | /// Clean up any resources being used. 13 | /// 14 | /// true if managed resources should be disposed; otherwise, false. 15 | protected override void Dispose(bool disposing) 16 | { 17 | if (disposing && (components != null)) 18 | { 19 | components.Dispose(); 20 | } 21 | base.Dispose(disposing); 22 | } 23 | 24 | #region Windows Form Designer generated code 25 | 26 | /// 27 | /// Required method for Designer support - do not modify 28 | /// the contents of this method with the code editor. 29 | /// 30 | private void InitializeComponent() 31 | { 32 | this.windowListCheckBox = new System.Windows.Forms.CheckedListBox(); 33 | this.SuspendLayout(); 34 | // 35 | // windowListCheckBox 36 | // 37 | this.windowListCheckBox.CheckOnClick = true; 38 | this.windowListCheckBox.Dock = System.Windows.Forms.DockStyle.Fill; 39 | this.windowListCheckBox.FormattingEnabled = true; 40 | this.windowListCheckBox.Location = new System.Drawing.Point(0, 0); 41 | this.windowListCheckBox.Name = "windowListCheckBox"; 42 | this.windowListCheckBox.Size = new System.Drawing.Size(328, 384); 43 | this.windowListCheckBox.TabIndex = 0; 44 | // 45 | // MainWindow 46 | // 47 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 48 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 49 | this.ClientSize = new System.Drawing.Size(328, 384); 50 | this.Controls.Add(this.windowListCheckBox); 51 | this.Name = "MainWindow"; 52 | this.Text = "Window Sharing Hider"; 53 | this.ResumeLayout(false); 54 | 55 | } 56 | 57 | #endregion 58 | 59 | private System.Windows.Forms.CheckedListBox windowListCheckBox; 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /WindowSharingHider/MainWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using System.Linq; 4 | using System.Windows.Forms; 5 | 6 | namespace WindowSharingHider 7 | { 8 | public partial class MainWindow : Form 9 | { 10 | public class WindowInfo 11 | { 12 | public String Title { get; set; } 13 | public IntPtr Handle { get; set; } 14 | public Boolean stillExists = false; 15 | public override string ToString() 16 | { 17 | return Title; 18 | } 19 | } 20 | public MainWindow() 21 | { 22 | InitializeComponent(); 23 | var timer = new Timer(); 24 | timer.Interval = 500; 25 | timer.Tick += Timer_Tick; 26 | timer.Start(); 27 | } 28 | Boolean flagToPreserveSettings = false; 29 | private void Timer_Tick(object sender, EventArgs e) 30 | { 31 | foreach (WindowInfo window in windowListCheckBox.Items) window.stillExists = false; 32 | var currWindows = WindowHandler.GetVisibleWindows(); 33 | foreach (var window in currWindows) 34 | { 35 | var existingWindow = windowListCheckBox.Items.Cast().FirstOrDefault(i => i.Handle == window.Key); 36 | if (existingWindow != null) 37 | { 38 | existingWindow.stillExists = true; 39 | existingWindow.Title = window.Value; 40 | } 41 | else windowListCheckBox.Items.Add(new WindowInfo { Title = window.Value, Handle = window.Key, stillExists = true }); 42 | } 43 | foreach (var window in windowListCheckBox.Items.Cast().ToArray()) if (window.stillExists == false) windowListCheckBox.Items.Remove(window); 44 | foreach (var window in windowListCheckBox.Items.Cast().ToArray()) 45 | { 46 | var status = WindowHandler.GetWindowDisplayAffinity(window.Handle) > 0; 47 | var target = windowListCheckBox.GetItemChecked(windowListCheckBox.Items.IndexOf(window)); 48 | if (target != status && flagToPreserveSettings) 49 | { 50 | WindowHandler.SetWindowDisplayAffinity(window.Handle, target ? 0x11 : 0x0); 51 | status = WindowHandler.GetWindowDisplayAffinity(window.Handle) > 0; 52 | } 53 | windowListCheckBox.SetItemChecked(windowListCheckBox.Items.IndexOf(window), status); 54 | } 55 | flagToPreserveSettings = true; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /WindowSharingHider/MainWindow.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /WindowSharingHider/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace WindowSharingHider 8 | { 9 | static class Program 10 | { 11 | /// 12 | /// The main entry point for the application. 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | Application.EnableVisualStyles(); 18 | Application.SetCompatibleTextRenderingDefault(false); 19 | Application.Run(new MainWindow()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /WindowSharingHider/WindowHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.InteropServices; 4 | using System.Text; 5 | 6 | namespace WindowSharingHider 7 | { 8 | public static class WindowHandler 9 | { 10 | [DllImport("user32")] static extern Boolean EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam); 11 | [DllImport("user32")] static extern Boolean IsWindowVisible(IntPtr hWnd); 12 | [DllImport("dwmapi.dll")] static extern Int32 DwmGetWindowAttribute(IntPtr hwnd, Int32 dwAttribute, out Int32 pvAttribute, Int32 cbAttribute); 13 | 14 | [DllImport("user32")] static extern IntPtr GetWindowText(IntPtr hWnd, StringBuilder lpString, Int32 nMaxCount); 15 | [DllImport("user32")] static extern Int32 GetWindowTextLength(IntPtr hWnd); 16 | [DllImport("user32")] static extern Boolean GetWindowDisplayAffinity(IntPtr hWnd, out Int32 dwAffinity); 17 | [DllImport("user32")] static extern UInt32 GetWindowThreadProcessId(IntPtr hWnd, out Int32 processId); 18 | delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); 19 | 20 | [DllImport("kernel32")] static extern IntPtr OpenProcess(Int32 dwDesiredAccess, Boolean bInheritHandle, Int32 dwProcessId); 21 | [DllImport("kernel32")] static extern IntPtr GetModuleHandle(String lpModuleName); 22 | [DllImport("kernel32")] static extern IntPtr GetProcAddress(IntPtr hModule, String procName); 23 | [DllImport("kernel32")] static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, Int32 dwSize, UInt32 flAllocationType, UInt32 flProtect); 24 | [DllImport("kernel32")] static extern Int32 ReadProcessMemory(IntPtr hProcess, UInt64 lpBaseAddress, [In, Out] Byte[] buffer, Int32 size, out Int32 lpNumberOfBytesRead); 25 | [DllImport("kernel32")] static extern Boolean WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, Byte[] lpBuffer, Int32 nSize, out Int32 lpNumberOfBytesWritten); 26 | [DllImport("kernel32")] static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, UInt32 dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, UInt32 dwCreationFlags, IntPtr lpThreadId); 27 | [DllImport("kernel32")] static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds); 28 | [DllImport("kernel32")] static extern Int32 CloseHandle(IntPtr hObject); 29 | [DllImport("kernel32")] static extern Boolean VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, Int32 dwSize, Int32 dwFreeType); 30 | [DllImport("kernel32")] static extern Boolean IsWow64Process(IntPtr processHandle, out Boolean wow64Process); 31 | [DllImport("psapi")] static extern bool GetModuleInformation(IntPtr hProcess, IntPtr hModule, out MODULEINFO lpmodinfo, UInt32 cb); 32 | [DllImport("psapi")] static extern bool EnumProcessModulesEx(IntPtr hProcess, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U4)][In][Out] IntPtr[] lphModule, UInt32 cb, out UInt32 lpcbNeeded, UInt32 dwFilterFlag); 33 | [DllImport("psapi")] static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, [Out] StringBuilder lpBaseName, UInt32 nSize); 34 | [StructLayout(LayoutKind.Sequential)] 35 | public struct MODULEINFO 36 | { 37 | public IntPtr lpBaseOfDll; 38 | public UInt32 SizeOfImage; 39 | public IntPtr EntryPoint; 40 | } 41 | public static Dictionary GetVisibleWindows() 42 | { 43 | var windows = new Dictionary(); 44 | EnumWindows(delegate (IntPtr hWnd, IntPtr lParam) 45 | { 46 | if (!IsWindowVisible(hWnd)) return true; 47 | DwmGetWindowAttribute(hWnd, 14, out Int32 pvAttribute, 4); 48 | if (pvAttribute > 0) return true; 49 | var length = GetWindowTextLength(hWnd); 50 | if (length == 0) return true; 51 | var windowTextBuilder = new StringBuilder(length + 1); 52 | GetWindowText(hWnd, windowTextBuilder, windowTextBuilder.Capacity); 53 | var windowTitle = windowTextBuilder.ToString(); 54 | if (windowTitle == "Program Manager") windowTitle = "Desktop and Icons"; 55 | windows[hWnd] = windowTitle; 56 | return true; 57 | }, IntPtr.Zero); 58 | return windows; 59 | } 60 | public static Int32 GetWindowDisplayAffinity(IntPtr hWnd) 61 | { 62 | GetWindowDisplayAffinity(hWnd, out Int32 dwAffinity); 63 | return dwAffinity; 64 | } 65 | public static Int32 ReadInt32(IntPtr procHandle, UInt64 addr, Boolean is32Bit) 66 | { 67 | var buffer = new Byte[8]; 68 | ReadProcessMemory(procHandle, (UInt64)addr, buffer, 8, out _); 69 | return BitConverter.ToInt32(buffer, 0); 70 | } 71 | // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowdisplayaffinity current process has to own hWnd.. but does it really matter?? 72 | public static void SetWindowDisplayAffinity(IntPtr hWnd, Int32 dwAffinity) 73 | { 74 | GetWindowThreadProcessId(hWnd, out Int32 procId); 75 | var procHandle = OpenProcess(0x38, true, procId); 76 | if (!IsWow64Process(procHandle, out bool is32Bit)) is32Bit = IntPtr.Size == 4; 77 | 78 | var ptrs = new IntPtr[0]; 79 | EnumProcessModulesEx(procHandle, ptrs, 0, out UInt32 bytesNeeded, 3); 80 | var size = is32Bit ? 4 : 8; 81 | var moduleCount = bytesNeeded / size; 82 | ptrs = new IntPtr[moduleCount]; 83 | EnumProcessModulesEx(procHandle, ptrs, bytesNeeded, out _, 3); 84 | 85 | var SetWindowDisplayAffinityAddr = 0ul; 86 | for (var i = 0; i < moduleCount && SetWindowDisplayAffinityAddr == 0; i++) 87 | { 88 | var path = new StringBuilder(260); 89 | GetModuleFileNameEx(procHandle, ptrs[i], path, 260); 90 | 91 | if (path.ToString().ToLower().Contains("user32.dll")) 92 | { 93 | GetModuleInformation(procHandle, ptrs[i], out MODULEINFO info, (uint)(size * ptrs.Length)); 94 | var e_lfanew = ReadInt32(procHandle, (UInt64)info.lpBaseOfDll + 0x3C, is32Bit); 95 | var ntHeaders = info.lpBaseOfDll + e_lfanew; 96 | var optionalHeader = ntHeaders + 0x18; 97 | var dataDirectory = optionalHeader + (is32Bit ? 0x60 : 0x70); 98 | var exportDirectory = info.lpBaseOfDll + ReadInt32(procHandle, (UInt64)dataDirectory, is32Bit); 99 | var names = info.lpBaseOfDll + ReadInt32(procHandle, (UInt64)exportDirectory + 0x20, is32Bit); 100 | var ordinals = info.lpBaseOfDll + ReadInt32(procHandle, (UInt64)exportDirectory + 0x24, is32Bit); 101 | var functions = info.lpBaseOfDll + ReadInt32(procHandle, (UInt64)exportDirectory + 0x1C, is32Bit); 102 | var numFuncs = ReadInt32(procHandle, (UInt64)exportDirectory + 0x18, is32Bit); 103 | 104 | for (var j = 0u; j < numFuncs && SetWindowDisplayAffinityAddr == 0; j++) 105 | { 106 | var offset = (UInt64)ReadInt32(procHandle, (UInt64)names + j * 4, is32Bit); 107 | var buffer = new Byte[32]; 108 | ReadProcessMemory(procHandle, (UInt64)info.lpBaseOfDll + offset, buffer, 32, out _); 109 | var name = Encoding.UTF8.GetString(buffer); 110 | var ordinal = (UInt64)(ReadInt32(procHandle, (UInt64)ordinals + j * 2, is32Bit) & 0xFFFF); 111 | var address = (UInt64)info.lpBaseOfDll + (UInt64)ReadInt32(procHandle, (UInt64)functions + ordinal * 4, is32Bit); 112 | if (name.StartsWith("SetWindowDisplayAffinity")) SetWindowDisplayAffinityAddr = address; 113 | } 114 | } 115 | } 116 | 117 | var asm = new List(); 118 | if (is32Bit) 119 | { 120 | asm.Add(0x68); // push 121 | asm.AddRange(BitConverter.GetBytes((UInt32)dwAffinity)); 122 | asm.Add(0x68); // push 123 | asm.AddRange(BitConverter.GetBytes((UInt32)hWnd)); 124 | asm.Add(0xB8); // mov eax 125 | asm.AddRange(BitConverter.GetBytes((UInt32)SetWindowDisplayAffinityAddr)); 126 | asm.AddRange(new Byte[] { 0xFF, 0xD0 }); // call eax 127 | } 128 | else 129 | { 130 | asm.AddRange(new Byte[] { 0x48, 0x83, 0xEC, 0x30 }); // sub rsp 0x30 131 | 132 | asm.AddRange(new Byte[] { 0x48, 0xB9 }); // mov rcx 133 | asm.AddRange(BitConverter.GetBytes((UInt64)hWnd)); 134 | 135 | asm.AddRange(new Byte[] { 0x48, 0xBA }); // mov rdx 136 | asm.AddRange(BitConverter.GetBytes((UInt64)dwAffinity)); 137 | 138 | asm.AddRange(new Byte[] { 0x48, 0xB8 }); // mov rax 139 | asm.AddRange(BitConverter.GetBytes((UInt64)SetWindowDisplayAffinityAddr)); 140 | 141 | asm.AddRange(new Byte[] { 0xFF, 0xD0 }); // call rax 142 | asm.AddRange(new Byte[] { 0x48, 0x83, 0xC4, 0x30 }); // add rsp 0x30 143 | } 144 | asm.Add(0xC3); // ret 145 | var codePtr = VirtualAllocEx(procHandle, IntPtr.Zero, asm.Count, 0x1000, 0x40); 146 | WriteProcessMemory(procHandle, codePtr, asm.ToArray(), asm.Count, out Int32 bytesWritten); 147 | 148 | var thread = CreateRemoteThread(procHandle, IntPtr.Zero, 0, codePtr, IntPtr.Zero, 0, IntPtr.Zero); 149 | WaitForSingleObject(thread, 10000); 150 | VirtualFreeEx(procHandle, codePtr, 0, 0x8000); 151 | CloseHandle(procHandle); 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /WindowSharingHider/WindowSharingHider.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {9A4DE5B4-64FC-4B26-B1F6-A07904AC33F1} 8 | WinExe 9 | WindowSharingHider 10 | WindowSharingHider 11 | v4.7.2 12 | 512 13 | true 14 | true 15 | 16 | 17 | x64 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | x64 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | WindowSharingHider.Program 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | Form 54 | 55 | 56 | MainWindow.cs 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | MainWindow.cs 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /cert.pfx.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shalzuth/WindowSharingHider/4076ee3d4c6bd4b6e0065f5d2ba22229ca144759/cert.pfx.enc --------------------------------------------------------------------------------