-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix high CPU usage in KeePass search results on Windows 10
- Loading branch information
Showing
8 changed files
with
205 additions
and
132 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#nullable enable | ||
|
||
using HarmonyLib; | ||
using KeePass.Plugins; | ||
|
||
namespace KeePassTrayIconLockState.Fixes; | ||
|
||
public interface Fix { | ||
|
||
public void fix(IPluginHost pluginHost, Harmony harmony); | ||
|
||
} |
34 changes: 34 additions & 0 deletions
34
KeePassTrayIconLockState/Fixes/FixHighCpuInSearchResults.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#nullable enable | ||
|
||
using HarmonyLib; | ||
using KeePass.Plugins; | ||
using KeePass.UI; | ||
using System.Reflection; | ||
using System.Windows.Forms; | ||
|
||
namespace KeePassTrayIconLockState.Fixes; | ||
|
||
/// <summary> | ||
/// <para>On Windows 10 but not 11, Windows' Accessibility/UI Automation gets into an infinite loop sending <c>WM_GETOBJECT</c> (0x3D), <c>LVM_ISGROUPVIEWENABLED</c> (0x10AF), and <c>LVM_GETVIEW</c> (0x108F) messages to the KeePass search results view when it has at least 1 result.</para> | ||
/// <para>This results in high CPU usage (roughly 50% of one logical CPU core). It lasts until you hide the search results, for example by navigating to a different folder in your KeePass database.</para> | ||
/// <para>To work around this issue and prevent the high CPU usage, this fix will prevent the window process of the search results view from handling <c>LVM_ISGROUPVIEWENABLED</c> messages by returning early. Blocking <c>WM_GETOBJECT</c> or <c>LVM_GETVIEW</c> messages are not necessary to fix this issue.</para> | ||
/// </summary> | ||
public class FixHighCpuInSearchResults: Fix { | ||
|
||
private const int LVM_ISGROUPVIEWENABLED = 0x10AF; | ||
|
||
public void fix(IPluginHost pluginHost, Harmony harmony) { | ||
MethodInfo wndProc = AccessTools.Method(typeof(CustomListViewEx), "WndProc", [typeof(Message).MakeByRefType()]); | ||
|
||
HarmonyMethod onBeforeCustomListViewExWndProc = new(AccessTools.Method(typeof(FixHighCpuInSearchResults), nameof(ignoreIsGroupViewEnabled), [typeof(Message).MakeByRefType()])); | ||
|
||
harmony.Patch(wndProc, prefix: onBeforeCustomListViewExWndProc); | ||
} | ||
|
||
/// <returns><c>true</c> if <paramref name="m"/> will not cause high CPU, which allows WndProc to run; or <c>false</c> if it will cause high CPU, which causes WndProc to return early</returns> | ||
/// <remarks><see href="https://harmony.pardeike.net/articles/patching-prefix.html#changing-the-result-and-skipping-the-original"/></remarks> | ||
internal static bool ignoreIsGroupViewEnabled(ref Message m) { | ||
return m.Msg != LVM_ISGROUPVIEWENABLED; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#nullable enable | ||
|
||
using HarmonyLib; | ||
using KeePass.Plugins; | ||
using System.Collections.Generic; | ||
|
||
namespace KeePassTrayIconLockState.Fixes; | ||
|
||
public static class Fixes { | ||
|
||
public static IEnumerable<Fix> all { get; } = [ | ||
new FixHighCpuInSearchResults() | ||
]; | ||
|
||
public static void fixAll(IPluginHost host, Harmony harmony) { | ||
foreach (Fix fix in all) { | ||
fix.fix(host, harmony); | ||
} | ||
} | ||
|
||
} |
235 changes: 120 additions & 115 deletions
235
KeePassTrayIconLockState/KeePassTrayIconLockState.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,116 +1,121 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | ||
<PropertyGroup> | ||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||
<ProjectGuid>{E980ABDC-E56D-4E9C-A322-AFBE9D9092B4}</ProjectGuid> | ||
<OutputType>Library</OutputType> | ||
<AppDesignerFolder>Properties</AppDesignerFolder> | ||
<RootNamespace>KeePassTrayIconLockState</RootNamespace> | ||
<AssemblyName>KeePassTrayIconLockState</AssemblyName> | ||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion> | ||
<FileAlignment>512</FileAlignment> | ||
<Deterministic>true</Deterministic> | ||
<NoWarn>8524;8509</NoWarn> | ||
<LangVersion>latest</LangVersion> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | ||
<DebugSymbols>true</DebugSymbols> | ||
<DebugType>full</DebugType> | ||
<Optimize>false</Optimize> | ||
<OutputPath>bin\Debug\</OutputPath> | ||
<DefineConstants>DEBUG;TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||
<DebugType>pdbonly</DebugType> | ||
<Optimize>true</Optimize> | ||
<OutputPath>bin\Release\</OutputPath> | ||
<DefineConstants>TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Reference Include="System" /> | ||
<Reference Include="System.Core" /> | ||
<Reference Include="System.Drawing" /> | ||
<Reference Include="System.Windows.Forms" /> | ||
</ItemGroup> | ||
<Choose> | ||
<When Condition="'$(GITHUB_ACTIONS)' == 'true'"> | ||
<ItemGroup> | ||
<!-- In GitHub Actions CI, KeePass is installed by Chocolatey to the default installation directory --> | ||
<!-- The "KeePass" NuGet package is unfortunately unusable because it's not an official build with the same strong signing key, so this project's DLL won't be able to refer to KeePass at runtime --> | ||
<!-- PLGX packaging would fix this because KeePass would rewrite the dependency during runtime JIT compilation, but would also require the project to be build with C# 5, which is old and gross --> | ||
<Reference Include="KeePass"> | ||
<HintPath>C:\Program Files\KeePass Password Safe 2\KeePass.exe</HintPath> | ||
<Private>False</Private> | ||
</Reference> | ||
</ItemGroup> | ||
</When> | ||
<Otherwise> | ||
<ItemGroup> | ||
<!-- During development, use the KeePass installation directory on the development machine --> | ||
<Reference Include="KeePass"> | ||
<HintPath>..\..\..\..\..\..\Programs\Security\KeePass\KeePass.exe</HintPath> | ||
<Private>False</Private> | ||
</Reference> | ||
</ItemGroup> | ||
</Otherwise> | ||
</Choose> | ||
<ItemGroup> | ||
<Compile Include="DatabaseOpenState.cs" /> | ||
<Compile Include="KeePassTrayIconLockStateExt.cs" /> | ||
<Compile Include="Properties\AssemblyInfo.cs" /> | ||
<Compile Include="Resources.Designer.cs"> | ||
<AutoGen>True</AutoGen> | ||
<DesignTime>True</DesignTime> | ||
<DependentUpon>Resources.resx</DependentUpon> | ||
</Compile> | ||
<Compile Include="TrayIcon.cs" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<PackageReference Include="DarkNet"> | ||
<Version>2.3.0</Version> | ||
</PackageReference> | ||
<PackageReference Include="ILRepack.Lib.MSBuild.Task"> | ||
<Version>2.0.26</Version> | ||
</PackageReference> | ||
<PackageReference Include="KoKo"> | ||
<Version>2.2.0</Version> | ||
</PackageReference> | ||
<PackageReference Include="Lib.Harmony"> | ||
<Version>2.2.2</Version> | ||
</PackageReference> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<EmbeddedResource Include="Resources.resx"> | ||
<Generator>ResXFileCodeGenerator</Generator> | ||
<LastGenOutput>Resources.Designer.cs</LastGenOutput> | ||
</EmbeddedResource> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="Resources\locked.ico" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="Resources\unlocked.ico" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="Resources\unlocking.ico" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="Resources\plugin image.png" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="version.txt" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="Resources\unlocked-light.ico" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="Resources\unlocking-light.ico" /> | ||
</ItemGroup> | ||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | ||
<PropertyGroup> | ||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||
<ProjectGuid>{E980ABDC-E56D-4E9C-A322-AFBE9D9092B4}</ProjectGuid> | ||
<OutputType>Library</OutputType> | ||
<AppDesignerFolder>Properties</AppDesignerFolder> | ||
<RootNamespace>KeePassTrayIconLockState</RootNamespace> | ||
<AssemblyName>KeePassTrayIconLockState</AssemblyName> | ||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion> | ||
<FileAlignment>512</FileAlignment> | ||
<Deterministic>true</Deterministic> | ||
<NoWarn>8524;8509</NoWarn> | ||
<LangVersion>latest</LangVersion> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | ||
<DebugSymbols>true</DebugSymbols> | ||
<DebugType>full</DebugType> | ||
<Optimize>false</Optimize> | ||
<OutputPath>bin\Debug\</OutputPath> | ||
<DefineConstants>DEBUG;TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||
<DebugType>pdbonly</DebugType> | ||
<Optimize>true</Optimize> | ||
<OutputPath>bin\Release\</OutputPath> | ||
<DefineConstants>TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Reference Include="System" /> | ||
<Reference Include="System.Core" /> | ||
<Reference Include="System.Drawing" /> | ||
<Reference Include="System.Windows.Forms" /> | ||
</ItemGroup> | ||
<Choose> | ||
<When Condition="'$(GITHUB_ACTIONS)' == 'true'"> | ||
<ItemGroup> | ||
<!-- In GitHub Actions CI, KeePass is installed by Chocolatey to the default installation directory --> | ||
<!-- The "KeePass" NuGet package is unfortunately unusable because it's not an official build with the same strong signing key, so this project's DLL won't be able to refer to KeePass at runtime --> | ||
<!-- PLGX packaging would fix this because KeePass would rewrite the dependency during runtime JIT compilation, but would also require the project to be build with C# 5, which is old and gross --> | ||
<Reference Include="KeePass"> | ||
<HintPath>C:\Program Files\KeePass Password Safe 2\KeePass.exe</HintPath> | ||
<Private>False</Private> | ||
</Reference> | ||
</ItemGroup> | ||
</When> | ||
<Otherwise> | ||
<ItemGroup> | ||
<!-- During development, use the KeePass installation directory on the development machine --> | ||
<Reference Include="KeePass"> | ||
<HintPath>..\..\..\..\..\..\Programs\Security\KeePass\KeePass.exe</HintPath> | ||
<Private>False</Private> | ||
</Reference> | ||
</ItemGroup> | ||
</Otherwise> | ||
</Choose> | ||
<ItemGroup> | ||
<Compile Include="DatabaseOpenState.cs" /> | ||
<Compile Include="Fixes\Fix.cs" /> | ||
<Compile Include="Fixes\Fixes.cs" /> | ||
<Compile Include="Fixes\FixHighCpuInSearchResults.cs" /> | ||
<Compile Include="KeePassTrayIconLockStateExt.cs" /> | ||
<Compile Include="Properties\AssemblyInfo.cs" /> | ||
<Compile Include="Resources.Designer.cs"> | ||
<AutoGen>True</AutoGen> | ||
<DesignTime>True</DesignTime> | ||
<DependentUpon>Resources.resx</DependentUpon> | ||
</Compile> | ||
<Compile Include="TrayIcon.cs" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<PackageReference Include="DarkNet"> | ||
<Version>2.3.0</Version> | ||
</PackageReference> | ||
<PackageReference Include="ILRepack.Lib.MSBuild.Task"> | ||
<Version>2.0.26</Version> | ||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||
<PrivateAssets>all</PrivateAssets> | ||
</PackageReference> | ||
<PackageReference Include="KoKo"> | ||
<Version>2.2.0</Version> | ||
</PackageReference> | ||
<PackageReference Include="Lib.Harmony"> | ||
<Version>2.2.2</Version> | ||
</PackageReference> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<EmbeddedResource Include="Resources.resx"> | ||
<Generator>ResXFileCodeGenerator</Generator> | ||
<LastGenOutput>Resources.Designer.cs</LastGenOutput> | ||
</EmbeddedResource> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="Resources\locked.ico" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="Resources\unlocked.ico" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="Resources\unlocking.ico" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="Resources\plugin image.png" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="version.txt" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="Resources\unlocked-light.ico" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="Resources\unlocking-light.ico" /> | ||
</ItemGroup> | ||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.